KDevelop API Documentation

ASBeautifier.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1998,1999,2000,2001,2002 Tal Davidson. All rights reserved.
00003  *
00004  * ASBeautifier.cpp
00005  * by Tal Davidson (davidsont@bigfoot.com)
00006  * This file is a part of "Artistic Style" - an indentater and reformatter
00007  * of C, C++, C# and Java source files.
00008  *
00009  * The "Artistic Style" project, including all files needed to compile it,
00010  * is free software; you can redistribute it and/or use it and/or modify it
00011  * under the terms of the GNU General Public License as published 
00012  * by the Free Software Foundation; either version 2 of the License, 
00013  * or (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018  *
00019  * You should have received a copy of the GNU General Public
00020  * License along with this program.
00021  *
00022  * Patches:
00023  * 18 March 1999 - Brian Rampel -
00024  *       Fixed inverse insertion of spaces vs. tabs when in -t mode.
00025 */
00026 
00027 #include "compiler_defines.h"
00028 #include "astyle.h"
00029 
00030 #include <vector>
00031 #include <string>
00032 #include <cctype>
00033 #include <algorithm>
00034 #include <iostream>
00035 
00036 
00037 #define INIT_CONTAINER(container, value)     {if ( (container) != NULL ) delete (container); (container) = (value); }
00038 #define DELETE_CONTAINER(container)          {if ( (container) != NULL ) delete (container) ; }
00039 
00040 #ifdef USES_NAMESPACE
00041 using namespace std;
00042 #endif
00043 
00044 
00045 
00046 
00047 #ifdef USES_NAMESPACE
00048 namespace astyle
00049 {
00050 #endif
00051 
00052 bool ASBeautifier::calledInitStatic = false;
00053 
00054 vector<const string*> ASBeautifier::headers;
00055 vector<const string*> ASBeautifier::nonParenHeaders;
00056 vector<const string*> ASBeautifier::preBlockStatements;
00057 vector<const string*> ASBeautifier::assignmentOperators;
00058 vector<const string*> ASBeautifier::nonAssignmentOperators;
00059 
00060 /*
00061  * initialize the static vars
00062  */
00063 void ASBeautifier::initStatic()
00064 {
00065     if (calledInitStatic)
00066         return;
00067 
00068     calledInitStatic = true;
00069 
00070     headers.push_back(&AS_IF);
00071     headers.push_back(&AS_ELSE);
00072     headers.push_back(&AS_FOR);
00073     headers.push_back(&AS_WHILE);
00074     headers.push_back(&AS_DO);
00075     headers.push_back(&AS_TRY);
00076     headers.push_back(&AS_CATCH);
00077     headers.push_back(&AS_FINALLY);
00078     headers.push_back(&AS_SYNCHRONIZED);
00079     headers.push_back(&AS_SWITCH);
00080     headers.push_back(&AS_CASE);
00081     headers.push_back(&AS_DEFAULT);
00082     headers.push_back(&AS_FOREACH);
00083     headers.push_back(&AS_LOCK);
00084     headers.push_back(&AS_UNSAFE);
00085     headers.push_back(&AS_FIXED);
00086     headers.push_back(&AS_GET);
00087     headers.push_back(&AS_SET);
00088     headers.push_back(&AS_ADD);
00089     headers.push_back(&AS_REMOVE);
00090     //headers.push_back(&AS_PUBLIC);
00091     //headers.push_back(&AS_PRIVATE);
00092     //headers.push_back(&AS_PROTECTED);
00093 
00094     //headers.push_back(&AS_OPERATOR);
00095     headers.push_back(&AS_TEMPLATE);
00096     headers.push_back(&AS_CONST);
00097     
00098     headers.push_back(&AS_STATIC);
00099     headers.push_back(&AS_EXTERN);
00100 
00101     nonParenHeaders.push_back(&AS_ELSE);
00102     nonParenHeaders.push_back(&AS_DO);
00103     nonParenHeaders.push_back(&AS_TRY);
00104     nonParenHeaders.push_back(&AS_FINALLY);
00105     nonParenHeaders.push_back(&AS_STATIC);
00106     nonParenHeaders.push_back(&AS_CONST);
00107     nonParenHeaders.push_back(&AS_EXTERN);
00108     nonParenHeaders.push_back(&AS_CASE);
00109     nonParenHeaders.push_back(&AS_DEFAULT);
00110     nonParenHeaders.push_back(&AS_UNSAFE);
00111     nonParenHeaders.push_back(&AS_GET);
00112     nonParenHeaders.push_back(&AS_SET);
00113     nonParenHeaders.push_back(&AS_ADD);
00114     nonParenHeaders.push_back(&AS_REMOVE);
00115 
00116 
00117 
00118     nonParenHeaders.push_back(&AS_PUBLIC);
00119     nonParenHeaders.push_back(&AS_PRIVATE);
00120     nonParenHeaders.push_back(&AS_PROTECTED);
00121     nonParenHeaders.push_back(&AS_TEMPLATE);
00122     nonParenHeaders.push_back(&AS_CONST);
00124 
00125     preBlockStatements.push_back(&AS_CLASS);
00126     preBlockStatements.push_back(&AS_STRUCT);
00127     preBlockStatements.push_back(&AS_UNION);
00128     preBlockStatements.push_back(&AS_INTERFACE);
00129     preBlockStatements.push_back(&AS_NAMESPACE);
00130     preBlockStatements.push_back(&AS_THROWS);
00131     preBlockStatements.push_back(&AS_EXTERN);
00132 
00133     assignmentOperators.push_back(&AS_ASSIGN);
00134     assignmentOperators.push_back(&AS_PLUS_ASSIGN);
00135     assignmentOperators.push_back(&AS_MINUS_ASSIGN);
00136     assignmentOperators.push_back(&AS_MULT_ASSIGN);
00137     assignmentOperators.push_back(&AS_DIV_ASSIGN);
00138     assignmentOperators.push_back(&AS_MOD_ASSIGN);
00139     assignmentOperators.push_back(&AS_OR_ASSIGN);
00140     assignmentOperators.push_back(&AS_AND_ASSIGN);
00141     assignmentOperators.push_back(&AS_XOR_ASSIGN);
00142     assignmentOperators.push_back(&AS_GR_GR_GR_ASSIGN);
00143     assignmentOperators.push_back(&AS_GR_GR_ASSIGN);
00144     assignmentOperators.push_back(&AS_LS_LS_LS_ASSIGN);
00145     assignmentOperators.push_back(&AS_LS_LS_ASSIGN);
00146 
00147     assignmentOperators.push_back(&AS_RETURN);
00148 
00149     nonAssignmentOperators.push_back(&AS_EQUAL);
00150     nonAssignmentOperators.push_back(&AS_PLUS_PLUS);
00151     nonAssignmentOperators.push_back(&AS_MINUS_MINUS);
00152     nonAssignmentOperators.push_back(&AS_NOT_EQUAL);
00153     nonAssignmentOperators.push_back(&AS_GR_EQUAL);
00154     nonAssignmentOperators.push_back(&AS_GR_GR_GR);
00155     nonAssignmentOperators.push_back(&AS_GR_GR);
00156     nonAssignmentOperators.push_back(&AS_LS_EQUAL);
00157     nonAssignmentOperators.push_back(&AS_LS_LS_LS);
00158     nonAssignmentOperators.push_back(&AS_LS_LS);
00159     nonAssignmentOperators.push_back(&AS_ARROW);
00160     nonAssignmentOperators.push_back(&AS_AND);
00161     nonAssignmentOperators.push_back(&AS_OR);
00162 }
00163 
00167 ASBeautifier::ASBeautifier()
00168 {
00169     initStatic();
00170 
00171     waitingBeautifierStack = NULL;
00172     activeBeautifierStack = NULL;
00173     waitingBeautifierStackLengthStack = NULL;
00174     activeBeautifierStackLengthStack = NULL;
00175 
00176     headerStack  = NULL;
00177     tempStacks = NULL;
00178     blockParenDepthStack = NULL;
00179     blockStatementStack = NULL;
00180     parenStatementStack = NULL;
00181     bracketBlockStateStack = NULL;
00182     inStatementIndentStack = NULL;
00183     inStatementIndentStackSizeStack = NULL;
00184     parenIndentStack = NULL;
00185     sourceIterator = NULL;
00186 
00187     isMinimalConditinalIndentSet = false;
00188     shouldForceTabIndentation = false;
00189 
00190     setSpaceIndentation(4);
00191     setMaxInStatementIndentLength(40);
00192     setClassIndent(false);
00193     setSwitchIndent(false);
00194     setCaseIndent(false);
00195     setBlockIndent(false);
00196     setBracketIndent(false);
00197     setNamespaceIndent(false);
00198     setLabelIndent(false);
00199     setEmptyLineFill(false);
00200     setCStyle();
00201     setPreprocessorIndent(false);
00202 }
00203 
00204 ASBeautifier::ASBeautifier(const ASBeautifier &other)
00205 {
00206     waitingBeautifierStack = NULL;
00207     activeBeautifierStack = NULL;
00208     waitingBeautifierStackLengthStack = NULL;
00209     activeBeautifierStackLengthStack = NULL;
00210 
00211     headerStack  = new vector<const string*>;
00212     *headerStack = *other.headerStack;
00213 
00214     tempStacks = new vector< vector<const string*>* >;
00215     vector< vector<const string*>* >::iterator iter;
00216     for (iter = other.tempStacks->begin();
00217             iter != other.tempStacks->end();
00218             ++iter)
00219     {
00220         vector<const string*> *newVec = new vector<const string*>;
00221         *newVec = **iter;
00222         tempStacks->push_back(newVec);
00223     }
00224     blockParenDepthStack = new vector<int>;
00225     *blockParenDepthStack = *other.blockParenDepthStack;
00226 
00227     blockStatementStack = new vector<bool>;
00228     *blockStatementStack = *other.blockStatementStack;
00229 
00230     parenStatementStack =  new vector<bool>;
00231     *parenStatementStack = *other.parenStatementStack;
00232 
00233     bracketBlockStateStack = new vector<bool>;
00234     *bracketBlockStateStack = *other.bracketBlockStateStack;
00235 
00236     inStatementIndentStack = new vector<int>;
00237     *inStatementIndentStack = *other.inStatementIndentStack;
00238 
00239     inStatementIndentStackSizeStack = new vector<int>;
00240     *inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack;
00241 
00242     parenIndentStack = new vector<int>;
00243     *parenIndentStack = *other.parenIndentStack;
00244 
00245     sourceIterator = other.sourceIterator;
00246 
00247     indentString = other.indentString;
00248     currentHeader = other.currentHeader;
00249     previousLastLineHeader = other.previousLastLineHeader;
00250     immediatelyPreviousAssignmentOp = other.immediatelyPreviousAssignmentOp;
00251     isInQuote = other.isInQuote;
00252     isInComment = other.isInComment;
00253     isInCase = other.isInCase;
00254     isInQuestion = other.isInQuestion;
00255     isInStatement =other. isInStatement;
00256     isInHeader = other.isInHeader;
00257     isCStyle = other.isCStyle;
00258     isInOperator = other.isInOperator;
00259     isInTemplate = other.isInTemplate;
00260     isInConst = other.isInConst;
00261     classIndent = other.classIndent;
00262     isInClassHeader = other.isInClassHeader;
00263     isInClassHeaderTab = other.isInClassHeaderTab;
00264     switchIndent = other.switchIndent;
00265     caseIndent = other.caseIndent;
00266     namespaceIndent = other.namespaceIndent;
00267     bracketIndent = other.bracketIndent;
00268     blockIndent = other.blockIndent;
00269     labelIndent = other.labelIndent;
00270     preprocessorIndent = other.preprocessorIndent;
00271     parenDepth = other.parenDepth;
00272     indentLength = other.indentLength;
00273     blockTabCount = other.blockTabCount;
00274     leadingWhiteSpaces = other.leadingWhiteSpaces;
00275     maxInStatementIndent = other.maxInStatementIndent;
00276     templateDepth = other.templateDepth;
00277     quoteChar = other.quoteChar;
00278     prevNonSpaceCh = other.prevNonSpaceCh;
00279     currentNonSpaceCh = other.currentNonSpaceCh;
00280     currentNonLegalCh = other.currentNonLegalCh;
00281     prevNonLegalCh = other.prevNonLegalCh;
00282     isInConditional = other.isInConditional;
00283     minConditionalIndent = other.minConditionalIndent;
00284     prevFinalLineSpaceTabCount = other.prevFinalLineSpaceTabCount;
00285     prevFinalLineTabCount = other.prevFinalLineTabCount;
00286     emptyLineFill = other.emptyLineFill;
00287     probationHeader = other.probationHeader;
00288     isInDefine = other.isInDefine;
00289     isInDefineDefinition = other.isInDefineDefinition;
00290     backslashEndsPrevLine = other.backslashEndsPrevLine;
00291     defineTabCount = other.defineTabCount;
00292 }
00293 
00297 ASBeautifier::~ASBeautifier()
00298 {
00299     DELETE_CONTAINER( headerStack );
00300     DELETE_CONTAINER( tempStacks );
00301     DELETE_CONTAINER( blockParenDepthStack );
00302     DELETE_CONTAINER( blockStatementStack );
00303     DELETE_CONTAINER( parenStatementStack );
00304     DELETE_CONTAINER( bracketBlockStateStack );
00305     DELETE_CONTAINER( inStatementIndentStack );
00306     DELETE_CONTAINER( inStatementIndentStackSizeStack );
00307     DELETE_CONTAINER( parenIndentStack );
00308 
00309     //DELETE_CONTAINER( sourceIterator );
00310 }
00311 
00324 void ASBeautifier::init(ASSourceIterator *iter)
00325 {
00326     sourceIterator = iter;
00327     init();
00328 }
00329 
00333 void ASBeautifier::init()
00334 {
00335     INIT_CONTAINER( waitingBeautifierStack,  new vector<ASBeautifier*> );
00336     INIT_CONTAINER( activeBeautifierStack,  new vector<ASBeautifier*> );
00337 
00338     INIT_CONTAINER( waitingBeautifierStackLengthStack, new vector<int> );
00339     INIT_CONTAINER( activeBeautifierStackLengthStack, new vector<int> );
00340 
00341     INIT_CONTAINER( headerStack,  new vector<const string*> );
00342     INIT_CONTAINER( tempStacks, new vector< vector<const string*>* > );
00343     tempStacks->push_back(new vector<const string*>);
00344 
00345     INIT_CONTAINER( blockParenDepthStack, new vector<int> );
00346     INIT_CONTAINER( blockStatementStack, new vector<bool> );
00347     INIT_CONTAINER( parenStatementStack, new vector<bool> );
00348 
00349     INIT_CONTAINER( bracketBlockStateStack, new vector<bool> );
00350     bracketBlockStateStack->push_back(true);
00351 
00352     INIT_CONTAINER( inStatementIndentStack, new vector<int> );
00353     INIT_CONTAINER( inStatementIndentStackSizeStack, new vector<int> );
00354     inStatementIndentStackSizeStack->push_back(0);
00355     INIT_CONTAINER( parenIndentStack, new vector<int> );
00356 
00357     immediatelyPreviousAssignmentOp = NULL;
00358     previousLastLineHeader = NULL;
00359 
00360     isInQuote = false;
00361     isInComment = false;
00362     isInStatement = false;
00363     isInCase = false;
00364     isInQuestion = false;
00365     isInClassHeader = false;
00366     isInClassHeaderTab = false;
00367     isInHeader = false;
00368     isInOperator = false;
00369     isInTemplate = false;
00370     isInConst = false;
00371     isInConditional = false;
00372     templateDepth = 0;
00373     parenDepth=0;
00374     blockTabCount = 0;
00375     leadingWhiteSpaces = 0;
00376     prevNonSpaceCh = '{';
00377     currentNonSpaceCh = '{';
00378     prevNonLegalCh = '{';
00379     currentNonLegalCh = '{';
00380     prevFinalLineSpaceTabCount = 0;
00381     prevFinalLineTabCount = 0;
00382     probationHeader = NULL;
00383     backslashEndsPrevLine = false;
00384     isInDefine = false;
00385     isInDefineDefinition = false;
00386     defineTabCount = 0;
00387 }
00388 
00392 void ASBeautifier::setCStyle()
00393 {
00394     isCStyle = true;
00395 }
00396 
00400 void ASBeautifier::setJavaStyle()
00401 {
00402     isCStyle = false;
00403 }
00404 
00408 void ASBeautifier::setTabIndentation(int length, bool forceTabs)
00409 {
00410     indentString = "\t";
00411     indentLength = length;
00412     shouldForceTabIndentation = forceTabs;
00413 
00414     if (!isMinimalConditinalIndentSet)
00415         minConditionalIndent = indentLength * 2;
00416 }
00417 
00423 void ASBeautifier::setSpaceIndentation(int length)
00424 {
00425     indentString=string(length, ' ');
00426     indentLength = length;
00427 
00428     if (!isMinimalConditinalIndentSet)
00429         minConditionalIndent = indentLength * 2;
00430 }
00431 
00437 void ASBeautifier::setMaxInStatementIndentLength(int max)
00438 {
00439     maxInStatementIndent = max;
00440 }
00441 
00447 void ASBeautifier::setMinConditionalIndentLength(int min)
00448 {
00449     minConditionalIndent = min;
00450     isMinimalConditinalIndentSet = true;
00451 }
00452 
00459 void ASBeautifier::setBracketIndent(bool state)
00460 {
00461     bracketIndent = state;
00462 }
00463 
00470 void ASBeautifier::setBlockIndent(bool state)
00471 {
00472     if (state)
00473         setBracketIndent(false); // so that we don't have both bracket and block indent
00474     blockIndent = state;
00475 }
00476 
00483 void ASBeautifier::setClassIndent(bool state)
00484 {
00485     classIndent = state;
00486 }
00487 
00494 void ASBeautifier::setSwitchIndent(bool state)
00495 {
00496     switchIndent = state;
00497 }
00498 
00505 void ASBeautifier::setCaseIndent(bool state)
00506 {
00507     caseIndent = state;
00508 }
00516 void ASBeautifier::setNamespaceIndent(bool state)
00517 {
00518     namespaceIndent = state;
00519 }
00520 
00530 void ASBeautifier::setLabelIndent(bool state)
00531 {
00532     labelIndent = state;
00533 }
00534 
00541 void ASBeautifier::setPreprocessorIndent(bool state)
00542 {
00543     preprocessorIndent = state;
00544 }
00545 
00554 void ASBeautifier::setEmptyLineFill(bool state)
00555 {
00556     emptyLineFill = state;
00557 }
00558 
00564 bool ASBeautifier::hasMoreLines() const
00565 {
00566     return sourceIterator->hasMoreLines();
00567 }
00568 
00574 string ASBeautifier::nextLine()
00575 {
00576     return beautify(sourceIterator->nextLine());
00577 }
00578 
00587 string ASBeautifier::beautify(const string &originalLine)
00588 {
00589     string line;
00590     bool isInLineComment = false;
00591     bool lineStartsInComment = false;
00592     bool isInClass = false;
00593     bool isInSwitch = false;
00594     bool isImmediatelyAfterConst = false;
00595     bool isSpecialChar = false;
00596     char ch = ' ';
00597     char prevCh;
00598     string outBuffer; // the newly idented line is bufferd here
00599     int tabCount = 0;
00600     const string *lastLineHeader = NULL;
00601     bool closingBracketReached = false;
00602     int spaceTabCount = 0;
00603     char tempCh;
00604     int headerStackSize = headerStack->size();
00605     //bool isLineInStatement = isInStatement;
00606     bool shouldIndentBrackettedLine = true;
00607     int lineOpeningBlocksNum = 0;
00608     int lineClosingBlocksNum = 0;
00609     bool previousLineProbation = (probationHeader != NULL);
00610     int i;
00611 
00612     currentHeader = NULL;
00613 
00614     lineStartsInComment = isInComment;
00615 
00616     // handle and remove white spaces around the line:
00617     // If not in comment, first find out size of white space before line,
00618     // so that possible comments starting in the line continue in
00619     // relation to the preliminary white-space.
00620     if (!isInComment)
00621     {
00622         leadingWhiteSpaces = 0;
00623         while (leadingWhiteSpaces<(int)originalLine.length() && originalLine[leadingWhiteSpaces] <= 0x20)
00624             leadingWhiteSpaces++;
00625 
00626         line = trim(originalLine);
00627     }
00628     else
00629     {
00630         int trimSize;
00631         for (trimSize=0;
00632                 trimSize < (int)originalLine.length() && trimSize<leadingWhiteSpaces && originalLine[trimSize] <= 0x20 ;
00633                 trimSize++)
00634             ;
00635         line = originalLine.substr(trimSize);
00636     }
00637 
00638 
00639     if (line.length() == 0)
00640     {
00641         if (emptyLineFill)
00642             return preLineWS(prevFinalLineSpaceTabCount, prevFinalLineTabCount);
00643         else
00644             return line;
00645     }
00646 
00647     // handle preprocessor commands
00648 
00649     if (isCStyle && !isInComment && (line[0] == '#' || backslashEndsPrevLine))
00650     {
00651         if (line[0] == '#')
00652         {
00653             string preproc = trim(string(line.c_str() + 1));
00654 
00655 
00656             // When finding a multi-lined #define statement, the original beautifier
00657             // 1. sets its isInDefineDefinition flag
00658             // 2. clones a new beautifier that will be used for the actual indentation
00659             //    of the #define. This clone is put into the activeBeautifierStack in order
00660             //    to be called for the actual indentation.
00661             // The original beautifier will have isInDefineDefinition = true, isInDefine = false
00662             // The cloned beautifier will have   isInDefineDefinition = true, isInDefine = true
00663             if (preprocessorIndent && preproc.COMPARE(0, 6, string("define")) == 0 &&  line[line.length() - 1] == '\\')
00664             {
00665                 if (!isInDefineDefinition)
00666                 {
00667                     ASBeautifier *defineBeautifier;
00668 
00669                     // this is the original beautifier
00670                     isInDefineDefinition = true;
00671 
00672                     // push a new beautifier into the active stack
00673                     // this breautifier will be used for the indentation of this define
00674                     defineBeautifier = new ASBeautifier(*this);
00675                     //defineBeautifier->init();
00676                     //defineBeautifier->isInDefineDefinition = true;
00677                     //defineBeautifier->beautify("");
00678                     activeBeautifierStack->push_back(defineBeautifier);
00679                 }
00680                 else
00681                 {
00682                     // the is the cloned beautifier that is in charge of indenting the #define.
00683                     isInDefine = true;
00684                 }
00685             }
00686             else if (preproc.COMPARE(0, 2, string("if")) == 0)
00687             {
00688                 // push a new beautifier into the stack
00689                 waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
00690                 activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
00691                 waitingBeautifierStack->push_back(new ASBeautifier(*this));
00692             }
00693             else if (preproc.COMPARE(0, 4/*2*/, string("else")) == 0)
00694             {
00695                 if (!waitingBeautifierStack->empty())
00696                 {
00697                     // MOVE current waiting beautifier to active stack.
00698                     activeBeautifierStack->push_back(waitingBeautifierStack->back());
00699                     waitingBeautifierStack->pop_back();
00700                 }
00701             }
00702             else if (preproc.COMPARE(0, 4, string("elif")) == 0)
00703             {
00704                 if (!waitingBeautifierStack->empty())
00705                 {
00706                     // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
00707                     activeBeautifierStack->push_back( new ASBeautifier( *(waitingBeautifierStack->back()) ) );
00708                 }
00709             }
00710             else if (preproc.COMPARE(0, 5, string("endif")) == 0)
00711             {
00712                 int stackLength;
00713                 ASBeautifier *beautifier;
00714 
00715                 if (!waitingBeautifierStackLengthStack->empty())
00716                 {
00717                     stackLength = waitingBeautifierStackLengthStack->back();
00718                     waitingBeautifierStackLengthStack->pop_back();
00719                     while ((int)waitingBeautifierStack->size() > stackLength)
00720                     {
00721                         beautifier = waitingBeautifierStack->back();
00722                         waitingBeautifierStack->pop_back();
00723                         delete beautifier;
00724                     }
00725                 }
00726 
00727                 if (!activeBeautifierStackLengthStack->empty())
00728                 {
00729                     stackLength = activeBeautifierStackLengthStack->back();
00730                     activeBeautifierStackLengthStack->pop_back();
00731                     while ((int)activeBeautifierStack->size() > stackLength)
00732                     {
00733                         beautifier = activeBeautifierStack->back();
00734                         activeBeautifierStack->pop_back();
00735                         delete beautifier;
00736                     }
00737                 }
00738 
00739 
00740             }
00741         }
00742 
00743         // check if the last char is a backslash
00744         if(line.length() > 0)
00745             backslashEndsPrevLine = (line[line.length() - 1] == '\\');
00746         else
00747             backslashEndsPrevLine = false;
00748 
00749         // check if this line ends a multi-line #define
00750         // if so, use the #define's cloned beautifier for the line's indentation
00751         // and then remove it from the active beautifier stack and delete it.
00752         if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine)
00753         {
00754             string beautifiedLine;
00755             ASBeautifier *defineBeautifier;
00756 
00757             isInDefineDefinition = false;
00758             defineBeautifier = activeBeautifierStack->back();
00759             activeBeautifierStack->pop_back();
00760 
00761             beautifiedLine = defineBeautifier->beautify(line);
00762             delete defineBeautifier;
00763             return beautifiedLine;
00764         }
00765 
00766         // unless this is a multi-line #define, return this precompiler line as is.
00767         if (!isInDefine && !isInDefineDefinition)
00768             return originalLine;
00769     }
00770 
00771     // if there exists any worker beautifier in the activeBeautifierStack,
00772     // then use it instead of me to indent the current line.
00773     if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty())
00774     {
00775         return activeBeautifierStack->back()->beautify(line);
00776     }
00777 
00778     // calculate preliminary indentation based on data from past lines
00779     if (!inStatementIndentStack->empty())
00780         spaceTabCount = inStatementIndentStack->back();
00781 
00782 
00783     for (i=0; i<headerStackSize; i++)
00784     {
00785         isInClass = false;
00786 
00787         if (blockIndent || (!(i>0 && (*headerStack)[i-1] != &AS_OPEN_BRACKET
00788                               && (*headerStack)[i] == &AS_OPEN_BRACKET)))
00789             ++tabCount;
00790 
00791         if (isCStyle && !namespaceIndent && i >= 1
00792                 && (*headerStack)[i-1] == &AS_NAMESPACE
00793                 && (*headerStack)[i] == &AS_OPEN_BRACKET)
00794             --tabCount;
00795 
00796         if (isCStyle && i >= 1
00797                 && (*headerStack)[i-1] == &AS_CLASS
00798                 && (*headerStack)[i] == &AS_OPEN_BRACKET )
00799         {
00800             if (classIndent)
00801                 ++tabCount;
00802             isInClass = true;
00803         }
00804 
00805         // is the switchIndent option is on, indent switch statements an additional indent.
00806         else if (switchIndent && i > 1 &&
00807                  (*headerStack)[i-1] == &AS_SWITCH &&
00808                  (*headerStack)[i] == &AS_OPEN_BRACKET
00809                 )
00810         {
00811             ++tabCount;
00812             isInSwitch = true;
00813         }
00814 
00815     }
00816 
00817     if (!lineStartsInComment
00818             && isCStyle 
00819             && isInClass 
00820             && classIndent 
00821             && headerStackSize >= 2
00822             &&(*headerStack)[headerStackSize-2] == &AS_CLASS
00823             && (*headerStack)[headerStackSize-1] == &AS_OPEN_BRACKET 
00824             && line[0] == '}')
00825         --tabCount;
00826 
00827     else if (!lineStartsInComment
00828             && isInSwitch 
00829             && switchIndent 
00830             && headerStackSize >= 2 
00831             && (*headerStack)[headerStackSize-2] == &AS_SWITCH 
00832             && (*headerStack)[headerStackSize-1] == &AS_OPEN_BRACKET 
00833             && line[0] == '}')
00834         --tabCount;
00835 
00836     if (isInClassHeader)
00837     {
00838         isInClassHeaderTab = true;
00839         tabCount += 2;
00840     }
00841 
00842     if (isInConditional)
00843     {
00844         --tabCount;
00845     }
00846 
00847 
00848     // parse characters in the current line.
00849 
00850     for (i=0; i<(int)line.length(); i++)
00851     {
00852         tempCh = line[i];
00853 
00854         prevCh = ch;
00855         ch = tempCh;
00856 
00857         outBuffer.append(1, ch);
00858 
00859         if (isWhiteSpace(ch))
00860             continue;
00861 
00862         // handle special characters (i.e. backslash+character such as \n, \t, ...)
00863         if (isSpecialChar)
00864         {
00865             isSpecialChar = false;
00866             continue;
00867         }
00868         if (!(isInComment || isInLineComment) && line.COMPARE(i, 2, string("\\\\")) == 0)
00869         {
00870             outBuffer.append(1, '\\');
00871             i++;
00872             continue;
00873         }
00874         if (!(isInComment || isInLineComment) && ch=='\\')
00875         {
00876             isSpecialChar = true;
00877             continue;
00878         }
00879 
00880         // handle quotes (such as 'x' and "Hello Dolly")
00881         if (!(isInComment || isInLineComment) && (ch=='"' || ch=='\''))
00882             if (!isInQuote)
00883             {
00884                 quoteChar = ch;
00885                 isInQuote = true;
00886             }
00887             else if (quoteChar == ch)
00888             {
00889                 isInQuote = false;
00890                 isInStatement = true;
00891                 continue;
00892             }
00893         if (isInQuote)
00894             continue;
00895 
00896         // handle comments
00897 
00898         if ( !(isInComment || isInLineComment) && line.COMPARE(i, 2, AS_OPEN_LINE_COMMENT) == 0 )
00899         {
00900             isInLineComment = true;
00901             outBuffer.append(1, '/');
00902             i++;
00903             continue;
00904         }
00905         else if ( !(isInComment || isInLineComment) && line.COMPARE(i, 2, AS_OPEN_COMMENT) == 0 )
00906         {
00907             isInComment = true;
00908             outBuffer.append(1, '*');
00909             i++;
00910             continue;
00911         }
00912         else if ( (isInComment || isInLineComment) && line.COMPARE(i, 2, AS_CLOSE_COMMENT) == 0 )
00913         {
00914             isInComment = false;
00915             outBuffer.append(1, '/');
00916             i++;
00917             continue;
00918         }
00919 
00920         if (isInComment||isInLineComment)
00921             continue;
00922 
00923         // if we have reached this far then we are NOT in a comment or string of special character...
00924 
00925         if (probationHeader != NULL)
00926         {
00927             if ( ((probationHeader == &AS_STATIC || probationHeader == &AS_CONST) && ch == '{')
00928                     || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
00929             {
00930                 // insert the probation header as a new header
00931                 isInHeader = true;
00932                 headerStack->push_back(probationHeader);
00933 
00934                 // handle the specific probation header
00935                 isInConditional = (probationHeader == &AS_SYNCHRONIZED);
00936                 if (probationHeader == &AS_CONST)
00937                     isImmediatelyAfterConst = true;
00938                 //  isInConst = true;
00947                 isInStatement = false;
00948                 // if the probation comes from the previous line, then indent by 1 tab count.
00949                 if (previousLineProbation && ch == '{')
00950                     tabCount++;
00951                 previousLineProbation = false;
00952             }
00953 
00954             // dismiss the probation header
00955             probationHeader = NULL;
00956         }
00957 
00958         prevNonSpaceCh = currentNonSpaceCh;
00959         currentNonSpaceCh = ch;
00960         if (!isLegalNameChar(ch) && ch != ',' && ch != ';' )
00961         {
00962             prevNonLegalCh = currentNonLegalCh;
00963             currentNonLegalCh = ch;
00964         }
00965 
00966         //if (isInConst)
00967         //{
00968         //    isInConst = false;
00969         //    isImmediatelyAfterConst = true;
00970         //}
00971 
00972         if (isInHeader)
00973         {
00974             isInHeader = false;
00975             currentHeader = headerStack->back();
00976         }
00977         else
00978             currentHeader = NULL;
00979 
00980         if (isCStyle && isInTemplate
00981                 && (ch == '<' || ch == '>')
00982                 &&  findHeader(line, i, nonAssignmentOperators) == NULL) //;
00983         {
00984             if (ch == '<')
00985             {
00986                 ++templateDepth;
00987             }
00988             else if (ch == '>')
00989             {
00990                 if (--templateDepth <= 0)
00991                 {
00992                     if (isInTemplate)
00993                         ch = ';';
00994                     else
00995                         ch = 't';
00996                     isInTemplate = false;
00997                     templateDepth = 0;
00998                 }
00999             }
01000         }
01001 
01002         // handle parenthesies
01003         if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
01004         {
01005             if (ch == '(' || ch == '[')
01006             {
01007                 if (parenDepth == 0)
01008                 {
01009                     parenStatementStack->push_back(isInStatement);
01010                     isInStatement = true;
01011                 }
01012                 parenDepth++;
01013 
01014                 inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
01015 
01016                 if (currentHeader != NULL)
01017                     registerInStatementIndent(line, i, spaceTabCount, minConditionalIndent/*indentLength*2*/, true);
01018                 else
01019                     registerInStatementIndent(line, i, spaceTabCount, 0, true);
01020             }
01021             else if (ch == ')' || ch == ']')
01022             {
01023                 parenDepth--;
01024                 if (parenDepth == 0)
01025                 {
01026                     isInStatement = parenStatementStack->back();
01027                     parenStatementStack->pop_back();
01028                     ch = ' ';
01029 
01030                     isInConditional = false;
01031                 }
01032 
01033                 if (!inStatementIndentStackSizeStack->empty())
01034                 {
01035                     int previousIndentStackSize = inStatementIndentStackSizeStack->back();
01036                     inStatementIndentStackSizeStack->pop_back();
01037                     while (previousIndentStackSize < (int)inStatementIndentStack->size())
01038                         inStatementIndentStack->pop_back();
01039 
01040                     if (!parenIndentStack->empty())
01041                     {
01042                         int poppedIndent = parenIndentStack->back();
01043                         parenIndentStack->pop_back();
01044 
01045                         if (i == 0)
01046                             spaceTabCount = poppedIndent;
01047                     }
01048                 }
01049             }
01050 
01051             continue;
01052         }
01053 
01054 
01055         if (ch == '{')
01056         {
01057             bool isBlockOpener = false;
01058 
01059             // first, check if '{' is a block-opener or an static-array opener
01060             isBlockOpener = ( (prevNonSpaceCh == '{' && bracketBlockStateStack->back())
01061                               || prevNonSpaceCh == '}'
01062                               || prevNonSpaceCh == ')'
01063                               || prevNonSpaceCh == ';'
01064                               || isInClassHeader
01065                               || isBlockOpener
01066                               || isImmediatelyAfterConst
01067                               || (isInDefine &&
01068                                   (prevNonSpaceCh == '('
01069                                    || prevNonSpaceCh == '_'
01070                                    || isalnum(prevNonSpaceCh))) );
01071 
01072             isInClassHeader = false;
01073             if (!isBlockOpener && currentHeader != NULL)
01074             {
01075                 for (int n=0; n < (int)nonParenHeaders.size(); n++)
01076                     if (currentHeader == nonParenHeaders[n])
01077                     {
01078                         isBlockOpener = true;
01079                         break;
01080                     }
01081             }
01082             bracketBlockStateStack->push_back(isBlockOpener);
01083             if (!isBlockOpener)
01084             {
01085                 inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
01086                 registerInStatementIndent(line, i, spaceTabCount, 0, true);
01087                 parenDepth++;
01088                 if (i == 0)
01089                     shouldIndentBrackettedLine = false;
01090 
01091                 continue;
01092             }
01093 
01094             // this bracket is a block opener...
01095 
01096             ++lineOpeningBlocksNum;
01097 
01098             if (isInClassHeader)
01099                 isInClassHeader = false;
01100             if (isInClassHeaderTab)
01101             {
01102                 isInClassHeaderTab = false;
01103                 tabCount -= 2;
01104             }
01105 
01106             blockParenDepthStack->push_back(parenDepth);
01107             blockStatementStack->push_back(isInStatement);
01108 
01109             inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size());
01110 
01111             blockTabCount += isInStatement? 1 : 0;
01112             parenDepth = 0;
01113             isInStatement = false;
01114 
01115             tempStacks->push_back(new vector<const string*>);
01116             headerStack->push_back(&AS_OPEN_BRACKET);
01117             lastLineHeader = &AS_OPEN_BRACKET; // <------
01118 
01119             continue;
01120         }
01121 
01122         //check if a header has been reached
01123         if (prevCh == ' ')
01124         {
01125             bool isIndentableHeader = true;
01126             const string *newHeader = findHeader(line, i, headers);
01127             if (newHeader != NULL)
01128             {
01129                 // if we reached here, then this is a header...
01130                 isInHeader = true;
01131 
01132                 vector<const string*> *lastTempStack;
01133                 if (tempStacks->empty())
01134                     lastTempStack = NULL;
01135                 else
01136                     lastTempStack = tempStacks->back();
01137 
01138                 // if a new block is opened, push a new stack into tempStacks to hold the
01139                 // future list of headers in the new block.
01140 
01141                 // take care of the special case: 'else if (...)'
01142                 if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
01143                 {
01144                     //spaceTabCount += indentLength; // to counter the opposite addition that occurs when the 'if' is registered below...
01145                     headerStack->pop_back();
01146                 }
01147 
01148                 // take care of 'else'
01149                 else if (newHeader == &AS_ELSE)
01150                 {
01151                     if (lastTempStack != NULL)
01152                     {
01153                         int indexOfIf = indexOf(*lastTempStack, &AS_IF); // <---
01154                         if (indexOfIf != -1)
01155                         {
01156                             // recreate the header list in headerStack up to the previous 'if'
01157                             // from the temporary snapshot stored in lastTempStack.
01158                             int restackSize = lastTempStack->size() - indexOfIf - 1;
01159                             for (int r=0; r<restackSize; r++)
01160                             {
01161                                 headerStack->push_back(lastTempStack->back());
01162                                 lastTempStack->pop_back();
01163                             }
01164                             if (!closingBracketReached)
01165                                 tabCount += restackSize;
01166                         }
01167                         /*
01168                          * If the above if is not true, i.e. no 'if' before the 'else',
01169                          * then nothing beautiful will come out of this...
01170                          * I should think about inserting an Exception here to notify the caller of this...
01171                          */
01172                     }
01173                 }
01174 
01175                 // check if 'while' closes a previous 'do'
01176                 else if (newHeader == &AS_WHILE)
01177                 {
01178                     if (lastTempStack != NULL)
01179                     {
01180                         int indexOfDo = indexOf(*lastTempStack, &AS_DO); // <---
01181                         if (indexOfDo != -1)
01182                         {
01183                             // recreate the header list in headerStack up to the previous 'do'
01184                             // from the temporary snapshot stored in lastTempStack.
01185                             int restackSize = lastTempStack->size() - indexOfDo - 1;
01186                             for (int r=0; r<restackSize; r++)
01187                             {
01188                                 headerStack->push_back(lastTempStack->back());
01189                                 lastTempStack->pop_back();
01190                             }
01191                             if (!closingBracketReached)
01192                                 tabCount += restackSize;
01193                         }
01194                     }
01195                 }
01196                 // check if 'catch' closes a previous 'try' or 'catch'
01197                 else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
01198                 {
01199                     if (lastTempStack != NULL)
01200                     {
01201                         int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
01202                         if (indexOfTry == -1)
01203                             indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
01204                         if (indexOfTry != -1)
01205                         {
01206                             // recreate the header list in headerStack up to the previous 'try'
01207                             // from the temporary snapshot stored in lastTempStack.
01208                             int restackSize = lastTempStack->size() - indexOfTry - 1;
01209                             for (int r=0; r<restackSize; r++)
01210                             {
01211                                 headerStack->push_back(lastTempStack->back());
01212                                 lastTempStack->pop_back();
01213                             }
01214 
01215                             if (!closingBracketReached)
01216                                 tabCount += restackSize;
01217                         }
01218                     }
01219                 }
01220                 else if (newHeader == &AS_CASE)
01221                 {
01222                     isInCase = true;
01223                     if (!caseIndent)
01224                         --tabCount;
01225                 }
01226                 else if(newHeader == &AS_DEFAULT)
01227                 {
01228                     isInCase = true;
01229                     if (!caseIndent)
01230                         --tabCount;
01231                 }
01232                 else if (newHeader == &AS_PUBLIC || newHeader == &AS_PROTECTED || newHeader == &AS_PRIVATE)
01233                 {
01234                     if (isCStyle && !isInClassHeader)
01235                         --tabCount;
01236                     isIndentableHeader = false;
01237                 }
01238                 //else if ((newHeader == &STATIC || newHeader == &SYNCHRONIZED) &&
01239                 //         !headerStack->empty() &&
01240                 //         (headerStack->back() == &STATIC || headerStack->back() == &SYNCHRONIZED))
01241                 //{
01242                 //    isIndentableHeader = false;
01243                 //}
01244                 else if (newHeader == &AS_STATIC
01245                          || newHeader == &AS_SYNCHRONIZED
01246                          || (newHeader == &AS_CONST && isCStyle))
01247                 {
01248                     if (!headerStack->empty() &&
01249                             (headerStack->back() == &AS_STATIC
01250                              || headerStack->back() == &AS_SYNCHRONIZED
01251                              || headerStack->back() == &AS_CONST))
01252                     {
01253                         isIndentableHeader = false;
01254                     }
01255                     else
01256                     {
01257                         isIndentableHeader = false;
01258                         probationHeader = newHeader;
01259                     }
01260                 }
01261                 else if (newHeader == &AS_CONST)
01262                 {
01263                     // this will be entered only if NOT in C style
01264                     // since otherwise the CONST would be found to be a probstion header...
01265 
01266                     //if (isCStyle)
01267                     //  isInConst = true;
01268                     isIndentableHeader = false;
01269                 }
01270                 /*
01271                               else if (newHeader == &OPERATOR)
01272                               {
01273                                   if (isCStyle)
01274                                       isInOperator = true;
01275                                   isIndentableHeader = false;
01276                               }
01277                 */
01278                 else if (newHeader == &AS_TEMPLATE)
01279                 {
01280                     if (isCStyle)
01281                         isInTemplate = true;
01282                     isIndentableHeader = false;
01283                 }
01284 
01285 
01286                 if (isIndentableHeader)
01287                 {
01288                     // 3.2.99
01289                     //spaceTabCount-=indentLength;
01290                     headerStack->push_back(newHeader);
01291                     isInStatement = false;
01292                     if (indexOf(nonParenHeaders, newHeader) == -1)
01293                     {
01294                         isInConditional = true;
01295                     }
01296                     lastLineHeader = newHeader;
01297                 }
01298                 else
01299                     isInHeader = false;
01300 
01301                 //lastLineHeader = newHeader;
01302 
01303                 outBuffer.append(newHeader->substr(1));
01304                 i += newHeader->length() - 1;
01305 
01306                 continue;
01307             }
01308         }
01309 
01310         if (isCStyle && !isalpha(prevCh)
01311                 && line.COMPARE(i, 8, AS_OPERATOR) == 0 && !isalnum(line[i+8]))
01312         {
01313             isInOperator = true;
01314             outBuffer.append(AS_OPERATOR.substr(1));
01315             i += 7;
01316             continue;
01317         }
01318 
01319         if (ch == '?')
01320             isInQuestion = true;
01321 
01322 
01323         // special handling of 'case' statements
01324         if (ch == ':')
01325         {
01326             if ((int)line.length() > i+1 && line[i+1] == ':') // look for ::
01327             {
01328                 ++i;
01329                 outBuffer.append(1, ':');
01330                 ch = ' ';
01331                 continue;
01332             }
01333 
01334             else if (isCStyle && isInClass && prevNonSpaceCh != ')')
01335             {
01336                 --tabCount;
01337                 // found a 'private:' or 'public:' inside a class definition
01338                 // so do nothing special
01339             }
01340 
01341             else if (isCStyle && isInClassHeader)
01342             {
01343 
01344                 // found a 'class A : public B' definition
01345                 // so do nothing special
01346             }
01347 
01348             else if (isInQuestion)
01349             {
01350                 isInQuestion = false;
01351             }
01352             else if (isCStyle && prevNonSpaceCh == ')')
01353             {
01354                 isInClassHeader = true;
01355                 if (i==0)
01356                     tabCount += 2;
01357             }
01358             else
01359             {
01360                 currentNonSpaceCh = ';'; // so that brackets after the ':' will appear as block-openers
01361                 if (isInCase)
01362                 {
01363                     isInCase = false;
01364                     ch = ';'; // from here on, treat char as ';'
01365                 }
01366 
01367 
01368                 else // is in a label (e.g. 'label1:')
01369                 {
01370                     if (labelIndent)
01371                         --tabCount; // unindent label by one indent
01372                     else
01373                         tabCount = 0; // completely flush indent to left
01374                 }
01375 
01376 
01377 
01378             }
01379         }
01380 
01381         if ((ch == ';'  || (parenDepth>0 && ch == ','))  && !inStatementIndentStackSizeStack->empty())
01382             while (inStatementIndentStackSizeStack->back() + (parenDepth>0 ? 1 : 0)  < (int)inStatementIndentStack->size())
01383                 inStatementIndentStack->pop_back();
01384 
01385 
01386         // handle ends of statements
01387         if ( (ch == ';' && parenDepth == 0) || ch == '}'/* || (ch == ',' && parenDepth == 0)*/)
01388         {
01389             if (ch == '}')
01390             {
01391                 // first check if this '}' closes a previous block, or a static array...
01392                 if (!bracketBlockStateStack->empty())
01393                 {
01394                     bool bracketBlockState = bracketBlockStateStack->back();
01395                     bracketBlockStateStack->pop_back();
01396                     if (!bracketBlockState)
01397                     {
01398                         if (!inStatementIndentStackSizeStack->empty())
01399                         {
01400                             // this bracket is a static array
01401 
01402                             int previousIndentStackSize = inStatementIndentStackSizeStack->back();
01403                             inStatementIndentStackSizeStack->pop_back();
01404                             while (previousIndentStackSize < (int)inStatementIndentStack->size())
01405                                 inStatementIndentStack->pop_back();
01406                             parenDepth--;
01407                             if (i == 0)
01408                                 shouldIndentBrackettedLine = false;
01409 
01410                             if (!parenIndentStack->empty())
01411                             {
01412                                 int poppedIndent = parenIndentStack->back();
01413                                 parenIndentStack->pop_back();
01414                                 if (i == 0)
01415                                     spaceTabCount = poppedIndent;
01416                             }
01417                         }
01418                         continue;
01419                     }
01420                 }
01421 
01422                 // this bracket is block closer...
01423 
01424                 ++lineClosingBlocksNum;
01425 
01426                 if(!inStatementIndentStackSizeStack->empty())
01427                     inStatementIndentStackSizeStack->pop_back();
01428 
01429                 if (!blockParenDepthStack->empty())
01430                 {
01431                     parenDepth = blockParenDepthStack->back();
01432                     blockParenDepthStack->pop_back();
01433                     isInStatement = blockStatementStack->back();
01434                     blockStatementStack->pop_back();
01435 
01436                     if (isInStatement)
01437                         blockTabCount--;
01438                 }
01439 
01440                 closingBracketReached = true;
01441                 int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACKET); // <---
01442                 if (headerPlace != -1)
01443                 {
01444                     const string *popped = headerStack->back();
01445                     while (popped != &AS_OPEN_BRACKET)
01446                     {
01447                         headerStack->pop_back();
01448                         popped = headerStack->back();
01449                     }
01450                     headerStack->pop_back();
01451 
01452                     if (!tempStacks->empty())
01453                     {
01454                         vector<const string*> *temp =  tempStacks->back();
01455                         tempStacks->pop_back();
01456                         delete temp;
01457                     }
01458                 }
01459 
01460 
01461                 ch = ' '; // needed due to cases such as '}else{', so that headers ('else' tn tih case) will be identified...
01462             }
01463 
01464             /*
01465              * Create a temporary snapshot of the current block's header-list in the
01466              * uppermost inner stack in tempStacks, and clear the headerStack up to
01467              * the begining of the block.
01468              * Thus, the next future statement will think it comes one indent past
01469              * the block's '{' unless it specifically checks for a companion-header
01470              * (such as a previous 'if' for an 'else' header) within the tempStacks,
01471              * and recreates the temporary snapshot by manipulating the tempStacks.
01472              */
01473             if (!tempStacks->back()->empty())
01474                 while (!tempStacks->back()->empty())
01475                     tempStacks->back()->pop_back();
01476             while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACKET)
01477             {
01478                 tempStacks->back()->push_back(headerStack->back());
01479                 headerStack->pop_back();
01480             }
01481 
01482             if (parenDepth == 0 && ch == ';')
01483                 isInStatement=false;
01484 
01485             isInClassHeader = false;
01486 
01487             continue;
01488         }
01489 
01490 
01491         // check for preBlockStatements ONLY if not within parenthesies
01492         // (otherwise 'struct XXX' statements would be wrongly interpreted...)
01493         if (prevCh == ' ' && !isInTemplate && parenDepth == 0)
01494         {
01495             const string *newHeader = findHeader(line, i, preBlockStatements);
01496             if (newHeader != NULL)
01497             {
01498                 isInClassHeader = true;
01499                 outBuffer.append(newHeader->substr(1));
01500                 i += newHeader->length() - 1;
01501                 //if (isCStyle)
01502                 headerStack->push_back(newHeader);
01503             }
01504         }
01505 
01506         // Handle operators
01507         //
01508 
01513 
01514         const string *foundAssignmentOp = NULL;
01515         const string *foundNonAssignmentOp = NULL;
01516 
01517         immediatelyPreviousAssignmentOp = NULL;
01518 
01519         // Check if an operator has been reached.
01520         foundAssignmentOp = findHeader(line, i, assignmentOperators, false); 
01521         foundNonAssignmentOp = findHeader(line, i, nonAssignmentOperators, false); 
01522 
01523         // Since findHeader's boundry checking was not used above, it is possible
01524         // that both an assignment op and a non-assignment op where found,
01525         // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the 
01526         // found operator.
01527         if (foundAssignmentOp != NULL && foundNonAssignmentOp != NULL)
01528             if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
01529                 foundAssignmentOp = NULL;
01530             else
01531                 foundNonAssignmentOp = NULL;
01532 
01533         if (foundNonAssignmentOp != NULL)
01534         {
01535             if (foundNonAssignmentOp->length() > 1)
01536             {
01537                 outBuffer.append(foundNonAssignmentOp->substr(1));
01538                 i += foundNonAssignmentOp->length() - 1;
01539             }
01540         }
01541 
01542         else if (foundAssignmentOp != NULL)
01543         {
01544             if (foundAssignmentOp->length() > 1)
01545             {
01546                 outBuffer.append(foundAssignmentOp->substr(1));
01547                 i += foundAssignmentOp->length() - 1;
01548             }
01549 
01550             if (!isInOperator && !isInTemplate)
01551             {
01552                 registerInStatementIndent(line, i, spaceTabCount, 0, false);
01553                 immediatelyPreviousAssignmentOp = foundAssignmentOp;
01554                 isInStatement = true;
01555             }
01556         }
01557 
01558 /*
01559         immediatelyPreviousAssignmentOp = NULL;
01560         bool isNonAssingmentOperator = false;
01561         for (int n = 0; n < nonAssignmentOperators.size(); n++)
01562             if (line.COMPARE(i, nonAssignmentOperators[n]->length(), *(nonAssignmentOperators[n])) == 0)
01563             {
01564                 if (nonAssignmentOperators[n]->length() > 1)
01565                 {
01566                     outBuffer.append(nonAssignmentOperators[n]->substr(1));
01567                     i += nonAssignmentOperators[n]->length() - 1;
01568                 }
01569                 isNonAssingmentOperator = true;
01570                 break;
01571             }
01572         if (!isNonAssingmentOperator)
01573         {
01574             for (int a = 0; a < assignmentOperators.size(); a++)
01575                 if (line.COMPARE(i, assignmentOperators[a]->length(), *(assignmentOperators[a])) == 0)
01576                 {
01577                     if (assignmentOperators[a]->length() > 1)
01578                     {
01579                         outBuffer.append(assignmentOperators[a]->substr(1));
01580                         i += assignmentOperators[a]->length() - 1;
01581                     }
01582 
01583                     if (!isInOperator && !isInTemplate)
01584                     {
01585                         registerInStatementIndent(line, i, spaceTabCount, 0, false);
01586                         immediatelyPreviousAssignmentOp = assignmentOperators[a];
01587                         isInStatement = true;
01588                     }
01589                     break;
01590                 }
01591         }
01592 */
01593 
01594         if (isInOperator)
01595             isInOperator = false;
01596     }
01597 
01598     // handle special cases of unindentation:
01599 
01600     /*
01601      * if '{' doesn't follow an immediately previous '{' in the headerStack
01602      * (but rather another header such as "for" or "if", then unindent it
01603      * by one indentation relative to its block.
01604      */
01605     //    cerr << endl << lineOpeningBlocksNum << " " <<  lineClosingBlocksNum << " " <<  previousLastLineHeader << endl;
01606 
01607     // indent #define lines with one less tab
01608     //if (isInDefine)
01609     //    tabCount -= defineTabCount-1;
01610 
01611 
01612     if (!lineStartsInComment
01613             && !blockIndent 
01614             && outBuffer.length()>0
01615             && outBuffer[0]=='{'
01616             && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum == lineClosingBlocksNum)
01617             && !(headerStack->size() > 1 && (*headerStack)[headerStack->size()-2] == &AS_OPEN_BRACKET)
01618             && shouldIndentBrackettedLine)
01619         --tabCount;
01620 
01621     else if (!lineStartsInComment
01622             && outBuffer.length()>0 
01623             && outBuffer[0]=='}' 
01624             && shouldIndentBrackettedLine )
01625         --tabCount;
01626 
01627     // correctly indent one-line-blocks...
01628     else if (!lineStartsInComment
01629              && outBuffer.length()>0
01630              && lineOpeningBlocksNum > 0
01631              && lineOpeningBlocksNum == lineClosingBlocksNum
01632              && previousLastLineHeader != NULL
01633              && previousLastLineHeader != &AS_OPEN_BRACKET)
01634         tabCount -= 1; //lineOpeningBlocksNum - (blockIndent ? 1 : 0);
01635 
01636     if (tabCount < 0)
01637         tabCount = 0;
01638 
01639     // take care of extra bracket indentatation option...
01640     if (bracketIndent && outBuffer.length()>0 && shouldIndentBrackettedLine)
01641         if (outBuffer[0]=='{' || outBuffer[0]=='}')
01642             tabCount++;
01643 
01644 
01645     if (isInDefine)
01646     {
01647         if (outBuffer[0] == '#')
01648         {
01649             string preproc = trim(string(outBuffer.c_str() + 1));
01650             if (preproc.COMPARE(0, 6, string("define")) == 0)
01651             {
01652                 if (!inStatementIndentStack->empty()
01653                         && inStatementIndentStack->back() > 0)
01654                 {
01655                     defineTabCount = tabCount;
01656                 }
01657                 else
01658                 {
01659                     defineTabCount = tabCount - 1;
01660                     tabCount--;
01661                 }
01662             }
01663         }
01664 
01665         tabCount -= defineTabCount;
01666     }
01667 
01668     if (tabCount < 0)
01669         tabCount = 0;
01670 
01671 
01672     // finally, insert indentations into begining of line
01673 
01674     prevFinalLineSpaceTabCount = spaceTabCount;
01675     prevFinalLineTabCount = tabCount;
01676 
01677     if (shouldForceTabIndentation) {
01678         tabCount += spaceTabCount / indentLength;
01679         spaceTabCount = spaceTabCount % indentLength;
01680     }
01681 
01682     outBuffer = preLineWS(spaceTabCount,tabCount) + outBuffer;
01683 
01684     if (lastLineHeader != NULL)
01685         previousLastLineHeader = lastLineHeader;
01686 
01687     return outBuffer;
01688 }
01689 
01690 
01691 string ASBeautifier::preLineWS(int spaceTabCount, int tabCount)
01692 {
01693     string ws;
01694 
01695     for (int i=0; i<tabCount; i++)
01696         ws += indentString;
01697 
01698     while ((spaceTabCount--) > 0)
01699         ws += string(" ");
01700 
01701     return ws;
01702 
01703 }
01704 
01708 void ASBeautifier::registerInStatementIndent(const string &line, int i, int spaceTabCount,
01709         int minIndent, bool updateParenStack)
01710 {
01711     int inStatementIndent;
01712     int remainingCharNum = line.length() - i;
01713     int nextNonWSChar = 1;
01714 
01715     nextNonWSChar = getNextProgramCharDistance(line, i);
01716 
01717     // if indent is around the last char in the line, indent instead 2 spaces from the previous indent
01718     if (nextNonWSChar == remainingCharNum)
01719     {
01720         int previousIndent = spaceTabCount;
01721         if (!inStatementIndentStack->empty())
01722             previousIndent = inStatementIndentStack->back();
01723 
01724         inStatementIndentStack->push_back(/*2*/ indentLength + previousIndent );
01725         if (updateParenStack)
01726             parenIndentStack->push_back( previousIndent );
01727         return;
01728     }
01729 
01730     if (updateParenStack)
01731         parenIndentStack->push_back(i+spaceTabCount);
01732 
01733     inStatementIndent = i + nextNonWSChar + spaceTabCount;
01734 
01735     if (i + nextNonWSChar < minIndent)
01736         inStatementIndent = minIndent + spaceTabCount;
01737 
01738     if (i + nextNonWSChar > maxInStatementIndent)
01739         inStatementIndent =  indentLength*2 + spaceTabCount;
01740 
01741 
01742 
01743     if (!inStatementIndentStack->empty() &&
01744             inStatementIndent < inStatementIndentStack->back())
01745         inStatementIndent = inStatementIndentStack->back();
01746 
01747     inStatementIndentStack->push_back(inStatementIndent);
01748 }
01749 
01754 int ASBeautifier::getNextProgramCharDistance(const string &line, int i)
01755 {
01756     bool inComment = false;
01757     int remainingCharNum = line.length() - i;
01758     int charDistance = 1;
01759     int ch;
01760 
01761     for (charDistance = 1; charDistance < remainingCharNum; charDistance++)
01762     {
01763         ch = line[i + charDistance];
01764         if (inComment)
01765         {
01766             if (line.COMPARE(i + charDistance, 2, AS_CLOSE_COMMENT) == 0)
01767             {
01768                 charDistance++;
01769                 inComment = false;
01770             }
01771             continue;
01772         }
01773         else if (isWhiteSpace(ch))
01774             continue;
01775         else if (ch == '/')
01776         {
01777             if (line.COMPARE(i + charDistance, 2, AS_OPEN_LINE_COMMENT) == 0)
01778                 return remainingCharNum;
01779             else if (line.COMPARE(i + charDistance, 2, AS_OPEN_COMMENT) == 0)
01780             {
01781                 charDistance++;
01782                 inComment = true;
01783             }
01784         }
01785         else
01786             return charDistance;
01787     }
01788 
01789     return charDistance;
01790 }
01791 
01792 
01799 bool ASBeautifier::isLegalNameChar(char ch) const
01800 {
01801     return (isalnum(ch) //(ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || (ch>='0' && ch<='9') ||
01802             || ch=='.' || ch=='_' || (!isCStyle && ch=='$') || (isCStyle && ch=='~'));
01803 }
01804 
01805 
01811 const string *ASBeautifier::findHeader(const string &line, int i, const vector<const string*> &possibleHeaders, bool checkBoundry)
01812 {
01813     int maxHeaders = possibleHeaders.size();
01814     const string *header = NULL;
01815     int p;
01816 
01817     for (p=0; p < maxHeaders; p++)
01818     {
01819         header = possibleHeaders[p];
01820         
01821         if (line.COMPARE(i, header->length(), *header) == 0)
01822         {
01823             // check that this is a header and not a part of a longer word
01824             // (e.g. not at its begining, not at its middle...)
01825             
01826             int lineLength = line.length();
01827             int headerEnd = i + header->length();
01828             char startCh = (*header)[0];   // first char of header
01829             char endCh = 0;                // char just after header
01830             char prevCh = 0;               // char just before header
01831 
01832             if (headerEnd < lineLength)
01833             {
01834                 endCh = line[headerEnd];
01835             }
01836             if (i > 0)
01837             {
01838                 prevCh = line[i-1];
01839             }
01840 
01841             if (!checkBoundry)
01842             {
01843                 return header;
01844             }
01845             else if (prevCh != 0 
01846                         && isLegalNameChar(startCh) 
01847                         && isLegalNameChar(prevCh))
01848             {
01849                 return NULL;
01850             }
01851             else if (headerEnd >= lineLength 
01852                     || !isLegalNameChar(startCh) 
01853                     || !isLegalNameChar(endCh))
01854             {
01855                 return header;
01856             }
01857             else
01858             {
01859                 return NULL;
01860             }
01861         }
01862     }
01863 
01864     return NULL;
01865 }
01866 
01867 
01874 bool ASBeautifier::isWhiteSpace(char ch) const
01875 {
01876     return (ch == ' ' || ch == '\t');
01877 }
01878 
01886 int ASBeautifier::indexOf(vector<const string*> &container, const string *element)
01887 {
01888     vector<const string*>::const_iterator where;
01889 
01890     where= find(container.begin(), container.end(), element);
01891     if (where == container.end())
01892         return -1;
01893     else
01894         return where - container.begin();
01895 }
01896 
01903 string ASBeautifier::trim(const string &str)
01904 {
01905 
01906     int start = 0;
01907     int end = str.length() - 1;
01908 
01909     while (start < end && isWhiteSpace(str[start]))
01910         start++;
01911 
01912     while (start <= end && isWhiteSpace(str[end]))
01913         end--;
01914 
01915     string returnStr(str, start, end+1-start);
01916     return returnStr;
01917 }
01918 
01919 #ifdef USES_NAMESPACE
01920 }
01921 #endif
01922 
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Mar 23 00:03:51 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003