[brlcad-commits] SF.net SVN: brlcad:[58267] brlcad/trunk
Open Source Solid Modeling CAD
Brought to you by:
brlcad
From: <sta...@us...> - 2013-10-23 06:03:26
|
Revision: 58267 http://sourceforge.net/p/brlcad/code/58267 Author: starseeker Date: 2013-10-23 06:03:20 +0000 (Wed, 23 Oct 2013) Log Message: ----------- Add the beginnings of style validation integration to BRL-CAD. This approach uses a source code formatter (currently astyle) and treats any difference between astyle's output and the formatting of the source files in the target's sources list as a compilation-haulting error. Currently enabled by ENABLE_STYLE_VALIDATION, but the astyle.opt file currently in use has nothing to do with what will be the final formatting standard - DO NOT MAKE SOURCE CODE FORMATTING CHANGES BASED ON CURRENT RESULTS! Other TODO items for this feature - modularize BRLCAD_ADDLIB logic into macro and add to executables targets as well, incorporate per-target headers lists so we can also enforce good formatting behavior in headers, modularize to allow other formatters than astyle (in cause the LGPLv3 is any sort of problem down the road...), test on anything other than Ubuntu Linux... etc. Modified Paths: -------------- brlcad/trunk/INSTALL brlcad/trunk/configure brlcad/trunk/misc/CMake/BRLCAD_Targets.cmake brlcad/trunk/misc/astyle.opt brlcad/trunk/src/other/CMakeLists.txt Added Paths: ----------- brlcad/trunk/misc/CMake/FindASTYLE.cmake brlcad/trunk/misc/CMake/astyle.cmake.in brlcad/trunk/src/other/astyle/ brlcad/trunk/src/other/astyle/ASBeautifier.cpp brlcad/trunk/src/other/astyle/ASEnhancer.cpp brlcad/trunk/src/other/astyle/ASFormatter.cpp brlcad/trunk/src/other/astyle/ASLocalizer.cpp brlcad/trunk/src/other/astyle/ASLocalizer.h brlcad/trunk/src/other/astyle/ASResource.cpp brlcad/trunk/src/other/astyle/CMakeLists.txt brlcad/trunk/src/other/astyle/LICENSE brlcad/trunk/src/other/astyle/README brlcad/trunk/src/other/astyle/astyle.h brlcad/trunk/src/other/astyle/astyle_main.cpp brlcad/trunk/src/other/astyle/astyle_main.h brlcad/trunk/src/other/astyle/gpl-3.0.txt brlcad/trunk/src/other/astyle.dist Modified: brlcad/trunk/INSTALL =================================================================== --- brlcad/trunk/INSTALL 2013-10-23 03:52:21 UTC (rev 58266) +++ brlcad/trunk/INSTALL 2013-10-23 06:03:20 UTC (rev 58267) @@ -462,6 +462,16 @@ Aliases: ENABLE_ZLIB, ENABLE_LIBZ +--- BRLCAD_ASTYLE --- + +Option for enabling and disabling compilation of the Artistic Style +(astyle) utility provided with BRL-CAD's source distribution. Default is AUTO, +responsive to the toplevel BRLCAD_BUNDLED_LIBS option and testing +first for a system version if BRLCAD_BUNDLED_LIBS is also AUTO. + +Aliases: ENABLE_RE2C + + --- BRLCAD_LEMON --- Option for enabling and disabling compilation of the lemon parser Modified: brlcad/trunk/configure =================================================================== --- brlcad/trunk/configure 2013-10-23 03:52:21 UTC (rev 58266) +++ brlcad/trunk/configure 2013-10-23 06:03:20 UTC (rev 58267) @@ -98,6 +98,10 @@ shift;; --disable-libz) options="$options -DBRLCAD_ZLIB=SYSTEM"; shift;; + --enable-re2c) options="$options -DBRLCAD_ASTYLE=BUNDLED"; + shift;; + --disable-re2c) options="$options -DBRLCAD_ASTYLE=SYSTEM"; + shift;; --enable-lemon) options="$options -DBRLCAD_LEMON=BUNDLED"; shift;; --disable-lemon) options="$options -DBRLCAD_LEMON=SYSTEM"; Modified: brlcad/trunk/misc/CMake/BRLCAD_Targets.cmake =================================================================== --- brlcad/trunk/misc/CMake/BRLCAD_Targets.cmake 2013-10-23 03:52:21 UTC (rev 58266) +++ brlcad/trunk/misc/CMake/BRLCAD_Targets.cmake 2013-10-23 06:03:20 UTC (rev 58267) @@ -259,11 +259,40 @@ FLAGS_TO_FILES("${srcslist}" ${libname}) endif(${lib_type} STREQUAL "MIXED") + # BRL-CAD style checking test + if(ENABLE_STYLE_VALIDATION) + set(stampfiles) + make_directory(${CMAKE_CURRENT_BINARY_DIR}/validation) + foreach(srcfile ${srcslist}) + get_filename_component(root_name ${srcfile} NAME_WE) + string(MD5 path_md5 "${CMAKE_CURRENT_SOURCE_DIR}/${srcfile}") + set(stampfile "${CMAKE_CURRENT_BINARY_DIR}/validation/${root_name}_${path_md5}.checked") + set(scriptfile "${CMAKE_CURRENT_BINARY_DIR}/validation/${root_name}_${path_md5}.cmake") + set(srcfile_tmp "${CMAKE_CURRENT_SOURCE_DIR}/${srcfile}") + set(outfile_tmp "${CMAKE_CURRENT_BINARY_DIR}/validation/${path_md5}") + set(stampfile_tmp "${stampfile}") + configure_file(${BRLCAD_SOURCE_DIR}/misc/CMake/astyle.cmake.in ${scriptfile}) + add_custom_command( + OUTPUT ${stampfile} + COMMAND ${CMAKE_COMMAND} -P ${scriptfile} + DEPENDS ${srcfile} ${ASTYLE_EXECUTABLE_TARGET} + COMMENT "Validating style of ${srcfile}" + ) + set(stampfiles ${stampfiles} ${stampfile}) + endforeach(srcfile ${srcslist}) + add_custom_target(validate_${libname} DEPENDS ${stampfiles}) + endif(ENABLE_STYLE_VALIDATION) + + # Handle "shared" libraries (with MSVC, these would be dynamic libraries) if(BUILD_SHARED_LIBS) add_library(${libname} SHARED ${srcslist}) + if(ENABLE_STYLE_VALIDATION) + add_dependencies(${libname} validate_${libname}) + endif(ENABLE_STYLE_VALIDATION) + # Make sure we don't end up with outputs named liblib... if(${libname} MATCHES "^lib*") set_target_properties(${libname} PROPERTIES PREFIX "") Added: brlcad/trunk/misc/CMake/FindASTYLE.cmake =================================================================== --- brlcad/trunk/misc/CMake/FindASTYLE.cmake (rev 0) +++ brlcad/trunk/misc/CMake/FindASTYLE.cmake 2013-10-23 06:03:20 UTC (rev 58267) @@ -0,0 +1,10 @@ +# The module defines the following variables: +# ASTYLE_EXECUTABLE - the path to the astyle executable +# +#============================================================================= + +find_program(ASTYLE_EXECUTABLE astyle DOC "path to the astyle executable") +mark_as_advanced(ASTYLE_EXECUTABLE) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(ASTYLE DEFAULT_MSG ASTYLE_EXECUTABLE) Property changes on: brlcad/trunk/misc/CMake/FindASTYLE.cmake ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: brlcad/trunk/misc/CMake/astyle.cmake.in =================================================================== --- brlcad/trunk/misc/CMake/astyle.cmake.in (rev 0) +++ brlcad/trunk/misc/CMake/astyle.cmake.in 2013-10-23 06:03:20 UTC (rev 58267) @@ -0,0 +1,54 @@ +# A S T Y L E . C M A K E . I N +# BRL-CAD +# +# Copyright (c) 2012-2013 United States Government as represented by +# the U.S. Army Research Laboratory. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials provided +# with the distribution. +# +# 3. The name of the author may not be used to endorse or promote +# products derived from this software without specific prior written +# permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +### +execute_process(COMMAND "@CMAKE_COMMAND@" -E remove -f "@stampfile_tmp@") +execute_process(COMMAND "@CMAKE_COMMAND@" -E copy "@srcfile_tmp@" "@outfile_tmp@") +execute_process(COMMAND "@ASTYLE_EXECUTABLE@" --options=@BRLCAD_SOURCE_DIR@/misc/astyle.opt "@outfile_tmp@" OUTPUT_QUIET ERROR_QUIET) +execute_process(COMMAND "@CMAKE_COMMAND@" -E remove -f "@outfile_tmp@.orig") +execute_process(COMMAND "@CMAKE_COMMAND@" -E compare_files "@srcfile_tmp@" "@outfile_tmp@" RESULT_VARIABLE CMDRESULT OUTPUT_QUIET ERROR_QUIET) +if(CMDRESULT) + message(FATAL_ERROR "Style failure: compare @srcfile_tmp@ with @outfile_tmp@ to see differences") +else(CMDRESULT) + execute_process(COMMAND "@CMAKE_COMMAND@" -E remove -f "@outfile_tmp@") + execute_process(COMMAND "@CMAKE_COMMAND@" -E touch "@stampfile_tmp@") +endif(CMDRESULT) + + +# Local Variables: +# tab-width: 8 +# mode: cmake +# indent-tabs-mode: t +# End: +# ex: shiftwidth=2 tabstop=8 Property changes on: brlcad/trunk/misc/CMake/astyle.cmake.in ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Modified: brlcad/trunk/misc/astyle.opt =================================================================== --- brlcad/trunk/misc/astyle.opt 2013-10-23 03:52:21 UTC (rev 58266) +++ brlcad/trunk/misc/astyle.opt 2013-10-23 06:03:20 UTC (rev 58267) @@ -2,7 +2,7 @@ style=k&r # Enable support for mixed tabs and spaces -indent=force-tab-x +indent=spaces=4 # Indent goto labels rather than making them flush on the left indent-labels @@ -13,9 +13,6 @@ # We don't want to add additional indentation to conditionals min-conditional-indent=0 -# Allow deeper indenting of statements -max-instatement-indent=120 - # Pad operators #pad-oper Modified: brlcad/trunk/src/other/CMakeLists.txt =================================================================== --- brlcad/trunk/src/other/CMakeLists.txt 2013-10-23 03:52:21 UTC (rev 58266) +++ brlcad/trunk/src/other/CMakeLists.txt 2013-10-23 06:03:20 UTC (rev 58267) @@ -175,6 +175,23 @@ # situations, CMake provides a variable CMAKE_CFG_INTDIR that will # insert the correct logic for config-dependent paths. + +# To enforce style guidelines rigorously, BRL-CAD bundles the +# Artistic Style code formatter. This tool is LGPLv3 licensed +# and its code can *not* be used in BRL-CAD itself - it +# is present striclty and only to be used as a tool in the +# compilation process. +set(astyle_ALIASES ENABLE_RE2C) +set(astyle_DESCRIPTION " +Option for enabling and disabling compilation of the Artistic Style +(astyle) utility provided with BRL-CAD's source distribution. Default is AUTO, +responsive to the toplevel BRLCAD_BUNDLED_LIBS option and testing +first for a system version if BRLCAD_BUNDLED_LIBS is also AUTO. +") +THIRD_PARTY_EXECUTABLE(astyle astyle "BRLCAD_LEVEL2" astyle_ALIASES astyle_DESCRIPTION) +DISTCLEAN(${CMAKE_CURRENT_BINARY_DIR}/astyle/Makefile) + + # For those wanting to use a system version of the LEMON parser # generator from sqlite, remember that the presence of /usr/bin/lemon # is not enough. LEMON needs a template file, lempar.c, and by Added: brlcad/trunk/src/other/astyle/ASBeautifier.cpp =================================================================== --- brlcad/trunk/src/other/astyle/ASBeautifier.cpp (rev 0) +++ brlcad/trunk/src/other/astyle/ASBeautifier.cpp 2013-10-23 06:03:20 UTC (rev 58267) @@ -0,0 +1,3204 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * ASBeautifier.cpp + * + * Copyright (C) 2006-2013 by Jim Pattee <ji...@em...> + * Copyright (C) 1998-2002 by Tal Davidson + * <http://www.gnu.org/licenses/lgpl-3.0.html> + * + * This file is a part of Artistic Style - an indentation and + * reformatting tool for C, C++, C# and Java source files. + * <http://astyle.sourceforge.net> + * + * Artistic Style is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Artistic Style is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Artistic Style. If not, see <http://www.gnu.org/licenses/>. + * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + */ + +#include "astyle.h" + +#include <algorithm> + + +namespace astyle { + +// this must be global +int g_preprocessorCppExternCBracket; + +/** + * ASBeautifier's constructor + * This constructor is called only once for each source file. + * The cloned ASBeautifier objects are created with the copy constructor. + */ +ASBeautifier::ASBeautifier() +{ + g_preprocessorCppExternCBracket = 0; + + waitingBeautifierStack = NULL; + activeBeautifierStack = NULL; + waitingBeautifierStackLengthStack = NULL; + activeBeautifierStackLengthStack = NULL; + + headerStack = NULL; + tempStacks = NULL; + blockParenDepthStack = NULL; + blockStatementStack = NULL; + parenStatementStack = NULL; + bracketBlockStateStack = NULL; + inStatementIndentStack = NULL; + inStatementIndentStackSizeStack = NULL; + parenIndentStack = NULL; + preprocIndentStack = NULL; + sourceIterator = NULL; + isModeManuallySet = false; + shouldForceTabIndentation = false; + setSpaceIndentation(4); + setMinConditionalIndentOption(MINCOND_TWO); + setMaxInStatementIndentLength(40); + classInitializerIndents = 1; + tabLength = 0; + setClassIndent(false); + setSwitchIndent(false); + setCaseIndent(false); + setBlockIndent(false); + setBracketIndent(false); + setNamespaceIndent(false); + setLabelIndent(false); + setEmptyLineFill(false); + setCStyle(); + setPreprocDefineIndent(false); + setPreprocConditionalIndent(false); + setAlignMethodColon(false); + + // initialize ASBeautifier member vectors + beautifierFileType = 9; // reset to an invalid type + headers = new vector<const string*>; + nonParenHeaders = new vector<const string*>; + assignmentOperators = new vector<const string*>; + nonAssignmentOperators = new vector<const string*>; + preBlockStatements = new vector<const string*>; + preCommandHeaders = new vector<const string*>; + indentableHeaders = new vector<const string*>; +} + +/** + * ASBeautifier's copy constructor + * Copy the vector objects to vectors in the new ASBeautifier + * object so the new object can be destroyed without deleting + * the vector objects in the copied vector. + * This is the reason a copy constructor is needed. + * + * Must explicitly call the base class copy constructor. + */ +ASBeautifier::ASBeautifier(const ASBeautifier &other) : ASBase(other) +{ + // these don't need to copy the stack + waitingBeautifierStack = NULL; + activeBeautifierStack = NULL; + waitingBeautifierStackLengthStack = NULL; + activeBeautifierStackLengthStack = NULL; + + // vector '=' operator performs a DEEP copy of all elements in the vector + + headerStack = new vector<const string*>; + *headerStack = *other.headerStack; + + tempStacks = copyTempStacks(other); + + blockParenDepthStack = new vector<int>; + *blockParenDepthStack = *other.blockParenDepthStack; + + blockStatementStack = new vector<bool>; + *blockStatementStack = *other.blockStatementStack; + + parenStatementStack = new vector<bool>; + *parenStatementStack = *other.parenStatementStack; + + bracketBlockStateStack = new vector<bool>; + *bracketBlockStateStack = *other.bracketBlockStateStack; + + inStatementIndentStack = new vector<int>; + *inStatementIndentStack = *other.inStatementIndentStack; + + inStatementIndentStackSizeStack = new vector<int>; + *inStatementIndentStackSizeStack = *other.inStatementIndentStackSizeStack; + + parenIndentStack = new vector<int>; + *parenIndentStack = *other.parenIndentStack; + + preprocIndentStack = new vector<pair<int, int> >; + *preprocIndentStack = *other.preprocIndentStack; + + // Copy the pointers to vectors. + // This is ok because the original ASBeautifier object + // is not deleted until end of job. + beautifierFileType = other.beautifierFileType; + headers = other.headers; + nonParenHeaders = other.nonParenHeaders; + assignmentOperators = other.assignmentOperators; + nonAssignmentOperators = other.nonAssignmentOperators; + preBlockStatements = other.preBlockStatements; + preCommandHeaders = other.preCommandHeaders; + indentableHeaders = other.indentableHeaders; + + // protected variables + // variables set by ASFormatter + // must also be updated in activeBeautifierStack + inLineNumber = other.inLineNumber; + horstmannIndentInStatement = other.horstmannIndentInStatement; + nonInStatementBracket = other.nonInStatementBracket; + lineCommentNoBeautify = other.lineCommentNoBeautify; + isElseHeaderIndent = other.isElseHeaderIndent; + isCaseHeaderCommentIndent = other.isCaseHeaderCommentIndent; + isNonInStatementArray = other.isNonInStatementArray; + isSharpAccessor = other.isSharpAccessor; + isSharpDelegate = other.isSharpDelegate; + isInExternC = other.isInExternC; + isInBeautifySQL = other.isInBeautifySQL; + isInIndentableStruct = other.isInIndentableStruct; + + // private variables + sourceIterator = other.sourceIterator; + currentHeader = other.currentHeader; + previousLastLineHeader = other.previousLastLineHeader; + probationHeader = other.probationHeader; + lastLineHeader = other.lastLineHeader; + indentString = other.indentString; + verbatimDelimiter = other.verbatimDelimiter; + isInQuote = other.isInQuote; + isInVerbatimQuote = other.isInVerbatimQuote; + haveLineContinuationChar = other.haveLineContinuationChar; + isInAsm = other.isInAsm; + isInAsmOneLine = other.isInAsmOneLine; + isInAsmBlock = other.isInAsmBlock; + isInComment = other.isInComment; + isInPreprocessorComment = other.isInPreprocessorComment; + isInHorstmannComment = other.isInHorstmannComment; + isInCase = other.isInCase; + isInQuestion = other.isInQuestion; + isInStatement = other.isInStatement; + isInHeader = other.isInHeader; + isInTemplate = other.isInTemplate; + isInDefine = other.isInDefine; + isInDefineDefinition = other.isInDefineDefinition; + classIndent = other.classIndent; + isInClassInitializer = other.isInClassInitializer; + isInClassHeaderTab = other.isInClassHeaderTab; + isInObjCMethodDefinition = other.isInObjCMethodDefinition; + isImmediatelyPostObjCMethodDefinition = other.isImmediatelyPostObjCMethodDefinition; + isInObjCInterface = other.isInObjCInterface; + isInEnum = other.isInEnum; + switchIndent = other.switchIndent; + caseIndent = other.caseIndent; + namespaceIndent = other.namespaceIndent; + bracketIndent = other.bracketIndent; + blockIndent = other.blockIndent; + labelIndent = other.labelIndent; + isInConditional = other.isInConditional; + isModeManuallySet = other.isModeManuallySet; + shouldForceTabIndentation = other.shouldForceTabIndentation; + emptyLineFill = other.emptyLineFill; + lineOpensWithLineComment = other.lineOpensWithLineComment; + lineOpensWithComment = other.lineOpensWithComment; + lineStartsInComment = other.lineStartsInComment; + backslashEndsPrevLine = other.backslashEndsPrevLine; + blockCommentNoIndent = other.blockCommentNoIndent; + blockCommentNoBeautify = other.blockCommentNoBeautify; + previousLineProbationTab = other.previousLineProbationTab; + lineBeginsWithOpenBracket = other.lineBeginsWithOpenBracket; + lineBeginsWithCloseBracket = other.lineBeginsWithCloseBracket; + shouldIndentBrackettedLine = other.shouldIndentBrackettedLine; + isInClass = other.isInClass; + isInSwitch = other.isInSwitch; + foundPreCommandHeader = other.foundPreCommandHeader; + foundPreCommandMacro = other.foundPreCommandMacro; + shouldAlignMethodColon = other.shouldAlignMethodColon; + shouldIndentPreprocDefine = other.shouldIndentPreprocDefine; + shouldIndentPreprocConditional = other.shouldIndentPreprocConditional; + indentCount = other.indentCount; + spaceIndentCount = other.spaceIndentCount; + spaceIndentObjCMethodDefinition = other.spaceIndentObjCMethodDefinition; + colonIndentObjCMethodDefinition = other.colonIndentObjCMethodDefinition; + lineOpeningBlocksNum = other.lineOpeningBlocksNum; + lineClosingBlocksNum = other.lineClosingBlocksNum; + fileType = other.fileType; + minConditionalOption = other.minConditionalOption; + minConditionalIndent = other.minConditionalIndent; + parenDepth = other.parenDepth; + indentLength = other.indentLength; + tabLength = other.tabLength; + blockTabCount = other.blockTabCount; + maxInStatementIndent = other.maxInStatementIndent; + classInitializerIndents = other.classInitializerIndents; + templateDepth = other.templateDepth; + squareBracketCount = other.squareBracketCount; + prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount; + prevFinalLineIndentCount = other.prevFinalLineIndentCount; + defineIndentCount = other.defineIndentCount; + quoteChar = other.quoteChar; + prevNonSpaceCh = other.prevNonSpaceCh; + currentNonSpaceCh = other.currentNonSpaceCh; + currentNonLegalCh = other.currentNonLegalCh; + prevNonLegalCh = other.prevNonLegalCh; +} + +/** + * ASBeautifier's destructor + */ +ASBeautifier::~ASBeautifier() +{ + deleteBeautifierContainer(waitingBeautifierStack); + deleteBeautifierContainer(activeBeautifierStack); + deleteContainer(waitingBeautifierStackLengthStack); + deleteContainer(activeBeautifierStackLengthStack); + deleteContainer(headerStack); + deleteTempStacksContainer(tempStacks); + deleteContainer(blockParenDepthStack); + deleteContainer(blockStatementStack); + deleteContainer(parenStatementStack); + deleteContainer(bracketBlockStateStack); + deleteContainer(inStatementIndentStack); + deleteContainer(inStatementIndentStackSizeStack); + deleteContainer(parenIndentStack); + deleteContainer(preprocIndentStack); +} + +/** + * initialize the ASBeautifier. + * + * This init() should be called every time a ABeautifier object is to start + * beautifying a NEW source file. + * It is called only when a new ASFormatter object is created. + * init() recieves a pointer to a ASSourceIterator object that will be + * used to iterate through the source code. + * + * @param iter a pointer to the ASSourceIterator or ASStreamIterator object. + */ +void ASBeautifier::init(ASSourceIterator* iter) +{ + sourceIterator = iter; + initVectors(); + ASBase::init(getFileType()); + + initContainer(waitingBeautifierStack, new vector<ASBeautifier*>); + initContainer(activeBeautifierStack, new vector<ASBeautifier*>); + + initContainer(waitingBeautifierStackLengthStack, new vector<int>); + initContainer(activeBeautifierStackLengthStack, new vector<int>); + + initContainer(headerStack, new vector<const string*>); + + initContainer(tempStacks, new vector<vector<const string*>*>); + tempStacks->push_back(new vector<const string*>); + + initContainer(blockParenDepthStack, new vector<int>); + initContainer(blockStatementStack, new vector<bool>); + initContainer(parenStatementStack, new vector<bool>); + initContainer(bracketBlockStateStack, new vector<bool>); + bracketBlockStateStack->push_back(true); + initContainer(inStatementIndentStack, new vector<int>); + initContainer(inStatementIndentStackSizeStack, new vector<int>); + inStatementIndentStackSizeStack->push_back(0); + initContainer(parenIndentStack, new vector<int>); + initContainer(preprocIndentStack, new vector<pair<int, int> >); + + previousLastLineHeader = NULL; + currentHeader = NULL; + + isInQuote = false; + isInVerbatimQuote = false; + haveLineContinuationChar = false; + isInAsm = false; + isInAsmOneLine = false; + isInAsmBlock = false; + isInComment = false; + isInPreprocessorComment = false; + isInHorstmannComment = false; + isInStatement = false; + isInCase = false; + isInQuestion = false; + isInClassInitializer = false; + isInClassHeaderTab = false; + isInObjCMethodDefinition = false; + isImmediatelyPostObjCMethodDefinition = false; + isInObjCInterface = false; + isInEnum = false; + isInHeader = false; + isInTemplate = false; + isInConditional = false; + + indentCount = 0; + spaceIndentCount = 0; + spaceIndentObjCMethodDefinition = 0; + colonIndentObjCMethodDefinition = 0; + lineOpeningBlocksNum = 0; + lineClosingBlocksNum = 0; + templateDepth = 0; + squareBracketCount = 0; + parenDepth = 0; + blockTabCount = 0; + prevFinalLineSpaceIndentCount = 0; + prevFinalLineIndentCount = 0; + defineIndentCount = 0; + prevNonSpaceCh = '{'; + currentNonSpaceCh = '{'; + prevNonLegalCh = '{'; + currentNonLegalCh = '{'; + quoteChar = ' '; + probationHeader = NULL; + lastLineHeader = NULL; + backslashEndsPrevLine = false; + lineOpensWithLineComment = false; + lineOpensWithComment = false; + lineStartsInComment = false; + isInDefine = false; + isInDefineDefinition = false; + lineCommentNoBeautify = false; + isElseHeaderIndent = false; + isCaseHeaderCommentIndent = false; + blockCommentNoIndent = false; + blockCommentNoBeautify = false; + previousLineProbationTab = false; + lineBeginsWithOpenBracket = false; + lineBeginsWithCloseBracket = false; + shouldIndentBrackettedLine = true; + isInClass = false; + isInSwitch = false; + foundPreCommandHeader = false; + foundPreCommandMacro = false; + + isNonInStatementArray = false; + isSharpAccessor = false; + isSharpDelegate = false; + isInExternC = false; + isInBeautifySQL = false; + isInIndentableStruct = false; + inLineNumber = 0; + horstmannIndentInStatement = 0; + nonInStatementBracket = 0; +} + +/* + * initialize the vectors + */ +void ASBeautifier::initVectors() +{ + if (fileType == beautifierFileType) // don't build unless necessary + return; + + beautifierFileType = fileType; + + headers->clear(); + nonParenHeaders->clear(); + assignmentOperators->clear(); + nonAssignmentOperators->clear(); + preBlockStatements->clear(); + preCommandHeaders->clear(); + indentableHeaders->clear(); + + ASResource::buildHeaders(headers, fileType, true); + ASResource::buildNonParenHeaders(nonParenHeaders, fileType, true); + ASResource::buildAssignmentOperators(assignmentOperators); + ASResource::buildNonAssignmentOperators(nonAssignmentOperators); + ASResource::buildPreBlockStatements(preBlockStatements, fileType); + ASResource::buildPreCommandHeaders(preCommandHeaders, fileType); + ASResource::buildIndentableHeaders(indentableHeaders); +} + +/** + * set indentation style to C/C++. + */ +void ASBeautifier::setCStyle() +{ + fileType = C_TYPE; +} + +/** + * set indentation style to Java. + */ +void ASBeautifier::setJavaStyle() +{ + fileType = JAVA_TYPE; +} + +/** + * set indentation style to C#. + */ +void ASBeautifier::setSharpStyle() +{ + fileType = SHARP_TYPE; +} + +/** + * set mode manually set flag + */ +void ASBeautifier::setModeManuallySet(bool state) +{ + isModeManuallySet = state; +} + +/** + * set tabLength equal to indentLength. + * This is done when tabLength is not explicitely set by + * "indent=force-tab-x" + * + */ +void ASBeautifier::setDefaultTabLength() +{ + tabLength = indentLength; +} + +/** + * indent using a different tab setting for indent=force-tab + * + * @param length number of spaces per tab. + */ +void ASBeautifier::setForceTabXIndentation(int length) +{ + // set tabLength instead of indentLength + indentString = "\t"; + tabLength = length; + shouldForceTabIndentation = true; +} + +/** + * indent using one tab per indentation + */ +void ASBeautifier::setTabIndentation(int length, bool forceTabs) +{ + indentString = "\t"; + indentLength = length; + shouldForceTabIndentation = forceTabs; +} + +/** + * indent using a number of spaces per indentation. + * + * @param length number of spaces per indent. + */ +void ASBeautifier::setSpaceIndentation(int length) +{ + indentString = string(length, ' '); + indentLength = length; +} + +/** + * set the maximum indentation between two lines in a multi-line statement. + * + * @param max maximum indentation length. + */ +void ASBeautifier::setMaxInStatementIndentLength(int max) +{ + maxInStatementIndent = max; +} + +/** + * set the minimum conditional indentation option. + * + * @param min minimal indentation option. + */ +void ASBeautifier::setMinConditionalIndentOption(int min) +{ + minConditionalOption = min; +} + +/** + * set minConditionalIndent from the minConditionalOption. + */ +void ASBeautifier::setMinConditionalIndentLength() +{ + if (minConditionalOption == MINCOND_ZERO) + minConditionalIndent = 0; + else if (minConditionalOption == MINCOND_ONE) + minConditionalIndent = indentLength; + else if (minConditionalOption == MINCOND_ONEHALF) + minConditionalIndent = indentLength / 2; + // minConditionalOption = INDENT_TWO + else minConditionalIndent = indentLength * 2; +} + +/** + * set the state of the bracket indentation option. If true, brackets will + * be indented one additional indent. + * + * @param state state of option. + */ +void ASBeautifier::setBracketIndent(bool state) +{ + bracketIndent = state; +} + +/** + * set the state of the block indentation option. If true, entire blocks + * will be indented one additional indent, similar to the GNU indent style. + * + * @param state state of option. + */ +void ASBeautifier::setBlockIndent(bool state) +{ + blockIndent = state; +} + +/** + * set the state of the class indentation option. If true, C++ class + * definitions will be indented one additional indent. + * + * @param state state of option. + */ +void ASBeautifier::setClassIndent(bool state) +{ + classIndent = state; +} + +/** + * set the state of the switch indentation option. If true, blocks of 'switch' + * statements will be indented one additional indent. + * + * @param state state of option. + */ +void ASBeautifier::setSwitchIndent(bool state) +{ + switchIndent = state; +} + +/** + * set the state of the case indentation option. If true, lines of 'case' + * statements will be indented one additional indent. + * + * @param state state of option. + */ +void ASBeautifier::setCaseIndent(bool state) +{ + caseIndent = state; +} + +/** + * set the state of the namespace indentation option. + * If true, blocks of 'namespace' statements will be indented one + * additional indent. Otherwise, NO indentation will be added. + * + * @param state state of option. + */ +void ASBeautifier::setNamespaceIndent(bool state) +{ + namespaceIndent = state; +} + +/** + * set the state of the label indentation option. + * If true, labels will be indented one indent LESS than the + * current indentation level. + * If false, labels will be flushed to the left with NO + * indent at all. + * + * @param state state of option. + */ +void ASBeautifier::setLabelIndent(bool state) +{ + labelIndent = state; +} + +/** + * set the state of the preprocessor indentation option. + * If true, multiline #define statements will be indented. + * + * @param state state of option. + */ +void ASBeautifier::setPreprocDefineIndent(bool state) +{ + shouldIndentPreprocDefine = state; +} + +void ASBeautifier::setPreprocConditionalIndent(bool state) +{ + shouldIndentPreprocConditional = state; +} + +/** + * set the state of the empty line fill option. + * If true, empty lines will be filled with the whitespace. + * of their previous lines. + * If false, these lines will remain empty. + * + * @param state state of option. + */ +void ASBeautifier::setEmptyLineFill(bool state) +{ + emptyLineFill = state; +} + +void ASBeautifier::setAlignMethodColon(bool state) +{ + shouldAlignMethodColon = state; +} + +/** + * get the file type. + */ +int ASBeautifier::getFileType() const +{ + return fileType; +} + +/** + * get the number of spaces per indent + * + * @return value of indentLength option. + */ +int ASBeautifier::getIndentLength(void) const +{ + return indentLength; +} + +/** + * get the char used for indentation, space or tab + * + * @return the char used for indentation. + */ +string ASBeautifier::getIndentString(void) const +{ + return indentString; +} + +/** + * get mode manually set flag + */ +bool ASBeautifier::getModeManuallySet() const +{ + return isModeManuallySet; +} + +/** + * get the state of the force tab indentation option. + * + * @return state of force tab indentation. + */ +bool ASBeautifier::getForceTabIndentation(void) const +{ + return shouldForceTabIndentation; +} + +/** + * get the state of the block indentation option. + * + * @return state of blockIndent option. + */ +bool ASBeautifier::getBlockIndent(void) const +{ + return blockIndent; +} + +/** + * get the state of the bracket indentation option. + * + * @return state of bracketIndent option. + */ +bool ASBeautifier::getBracketIndent(void) const +{ + return bracketIndent; +} + +/** + * get the state of the class indentation option. If true, blocks of + * the 'class' statement will be indented one additional indent. + * + * @return state of classIndent option. + */ +bool ASBeautifier::getClassIndent(void) const +{ + return classIndent; +} + +/** + * get the state of the switch indentation option. If true, blocks of + * the 'switch' statement will be indented one additional indent. + * + * @return state of switchIndent option. + */ +bool ASBeautifier::getSwitchIndent(void) const +{ + return switchIndent; +} + +/** + * get the state of the case indentation option. If true, lines of 'case' + * statements will be indented one additional indent. + * + * @return state of caseIndent option. + */ +bool ASBeautifier::getCaseIndent(void) const +{ + return caseIndent; +} + +/** + * get the state of the empty line fill option. + * If true, empty lines will be filled with the whitespace. + * of their previous lines. + * If false, these lines will remain empty. + * + * @return state of emptyLineFill option. + */ +bool ASBeautifier::getEmptyLineFill(void) const +{ + return emptyLineFill; +} + +/** + * get the state of the preprocessor indentation option. + * If true, preprocessor "define" lines will be indented. + * If false, preprocessor "define" lines will be unchanged. + * + * @return state of shouldIndentPreprocDefine option. + */ +bool ASBeautifier::getPreprocDefineIndent(void) const +{ + return shouldIndentPreprocDefine; +} + +/** + * get the length of the tab indentation option. + * + * @return length of tab indent option. + */ +int ASBeautifier::getTabLength(void) const +{ + return tabLength; +} + +/** + * beautify a line of source code. + * every line of source code in a source code file should be sent + * one after the other to the beautify method. + * + * @return the indented line. + * @param originalLine the original unindented line. + */ +string ASBeautifier::beautify(const string &originalLine) +{ + string line; + bool isInQuoteContinuation = isInVerbatimQuote | haveLineContinuationChar; + + currentHeader = NULL; + lastLineHeader = NULL; + blockCommentNoBeautify = blockCommentNoIndent; + isInClass = false; + isInSwitch = false; + lineBeginsWithOpenBracket = false; + lineBeginsWithCloseBracket = false; + shouldIndentBrackettedLine = true; + isInAsmOneLine = false; + lineOpensWithLineComment = false; + lineOpensWithComment = false; + lineStartsInComment = isInComment; + previousLineProbationTab = false; + haveLineContinuationChar = false; + lineOpeningBlocksNum = 0; + lineClosingBlocksNum = 0; + if (isImmediatelyPostObjCMethodDefinition) + clearObjCMethodDefinitionAlignment(); + + // handle and remove white spaces around the line: + // If not in comment, first find out size of white space before line, + // so that possible comments starting in the line continue in + // relation to the preliminary white-space. + if (isInQuoteContinuation) + { + // trim a single space added by ASFormatter, otherwise leave it alone + if (!(originalLine.length() == 1 && originalLine[0] == ' ')) + line = originalLine; + } + else if (isInComment || isInBeautifySQL) + { + // trim the end of comment and SQL lines + line = originalLine; + size_t trimEnd = line.find_last_not_of(" \t"); + if (trimEnd == string::npos) + trimEnd = 0; + else + trimEnd++; + if (trimEnd < line.length()) + line.erase(trimEnd); + // does a bracket open the line + size_t firstChar = line.find_first_not_of(" \t"); + if (firstChar != string::npos) + { + if (line[firstChar] == '{') + lineBeginsWithOpenBracket = true; + else if (line[firstChar] == '}') + lineBeginsWithCloseBracket = true; + } + } + else + { + line = trim(originalLine); + if (line.length() > 0) + { + if (line[0] == '{') + lineBeginsWithOpenBracket = true; + else if (line[0] == '}') + lineBeginsWithCloseBracket = true; + } + + isInHorstmannComment = false; + size_t j = line.find_first_not_of(" \t{"); + if (j != string::npos && line.compare(j, 2, "//") == 0) + lineOpensWithLineComment = true; + if (j != string::npos && line.compare(j, 2, "/*") == 0) + { + lineOpensWithComment = true; + size_t k = line.find_first_not_of(" \t"); + if (k != string::npos && line.compare(k, 1, "{") == 0) + isInHorstmannComment = true; + } + } + + if (line.length() == 0) + { + if (backslashEndsPrevLine) // must continue to clear variables + line = ' '; + else if (emptyLineFill && !isInQuoteContinuation + && (!headerStack->empty() || isInEnum)) + return preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount); + else + return line; + } + + // handle preprocessor commands + if (!isInComment + && !isInQuoteContinuation + && line.length() > 0 + && ((line[0] == '#' && !isIndentedPreprocessor(line, 0)) + || backslashEndsPrevLine)) + { + if (line[0] == '#' && !isInDefine) + { + string preproc = extractPreprocessorStatement(line); + processPreprocessor(preproc, line); + if (shouldIndentPreprocConditional && preproc.length() > 0) + { + if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") + { + pair<int, int> entry; + if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty()) + entry = activeBeautifierStack->back()->computePreprocessorIndent(); + else + entry = computePreprocessorIndent(); + preprocIndentStack->push_back(entry); + return preLineWS(preprocIndentStack->back().first, + preprocIndentStack->back().second) + line; + } + else if (preproc == "else" || preproc == "elif") + { + if (preprocIndentStack->size() > 0) // if no entry don't indent + return preLineWS(preprocIndentStack->back().first, + preprocIndentStack->back().second) + line; + } + else if (preproc == "endif") + { + if (preprocIndentStack->size() > 0) // if no entry don't indent + { + string indentedLine = preLineWS(preprocIndentStack->back().first, + preprocIndentStack->back().second) + line; + preprocIndentStack->pop_back(); + return indentedLine; + } + } + } + } + + // check if the last char is a backslash + if (line.length() > 0) + backslashEndsPrevLine = (line[line.length() - 1] == '\\'); + // comments within the definition line can be continued without the backslash + if (isInPreprocessorUnterminatedComment(line)) + backslashEndsPrevLine = true; + + // check if this line ends a multi-line #define + // if so, use the #define's cloned beautifier for the line's indentation + // and then remove it from the active beautifier stack and delete it. + if (!backslashEndsPrevLine && isInDefineDefinition && !isInDefine) + { + string beautifiedLine; + ASBeautifier* defineBeautifier; + + isInDefineDefinition = false; + defineBeautifier = activeBeautifierStack->back(); + activeBeautifierStack->pop_back(); + + beautifiedLine = defineBeautifier->beautify(line); + delete defineBeautifier; + return beautifiedLine; + } + + // unless this is a multi-line #define, return this precompiler line as is. + if (!isInDefine && !isInDefineDefinition) + return originalLine; + } + + // if there exists any worker beautifier in the activeBeautifierStack, + // then use it instead of me to indent the current line. + // variables set by ASFormatter must be updated. + if (!isInDefine && activeBeautifierStack != NULL && !activeBeautifierStack->empty()) + { + activeBeautifierStack->back()->inLineNumber = inLineNumber; + activeBeautifierStack->back()->horstmannIndentInStatement = horstmannIndentInStatement; + activeBeautifierStack->back()->nonInStatementBracket = nonInStatementBracket; + activeBeautifierStack->back()->lineCommentNoBeautify = lineCommentNoBeautify; + activeBeautifierStack->back()->isElseHeaderIndent = isElseHeaderIndent; + activeBeautifierStack->back()->isCaseHeaderCommentIndent = isCaseHeaderCommentIndent; + activeBeautifierStack->back()->isNonInStatementArray = isNonInStatementArray; + activeBeautifierStack->back()->isSharpAccessor = isSharpAccessor; + activeBeautifierStack->back()->isSharpDelegate = isSharpDelegate; + activeBeautifierStack->back()->isInExternC = isInExternC; + activeBeautifierStack->back()->isInBeautifySQL = isInBeautifySQL; + activeBeautifierStack->back()->isInIndentableStruct = isInIndentableStruct; + // must return originalLine not the trimmed line + return activeBeautifierStack->back()->beautify(originalLine); + } + + // Flag an indented header in case this line is a one-line block. + // The header in the header stack will be deleted by a one-line block. + bool isInExtraHeaderIndent = false; + if (!headerStack->empty() + && lineBeginsWithOpenBracket + && (headerStack->back() != &AS_OPEN_BRACKET + || probationHeader != NULL)) + isInExtraHeaderIndent = true; + + size_t iPrelim = headerStack->size(); + + // calculate preliminary indentation based on headerStack and data from past lines + computePreliminaryIndentation(); + + // parse characters in the current line. + parseCurrentLine(line); + + // handle special cases of indentation + adjustParsedLineIndentation(iPrelim, isInExtraHeaderIndent); + + // continuation line begining with a dot +// if (!isInComment && spaceIndentCount == 0 && line.length() > 0 && line[0] == '.') +// spaceIndentCount += indentLength; + + // Objective-C interface continuation line + if (isInObjCInterface && line.length() > 0 && line[0] != '@') + { + spaceIndentCount += indentLength; + } + + // Objective-C continuation line + if (isInObjCMethodDefinition) + { + // register indent for Objective-C continuation line + if (line.length() > 0 + && (line[0] == '-' || line[0] == '+')) + { + if (shouldAlignMethodColon) + { + colonIndentObjCMethodDefinition = line.find(':'); + } + else if (inStatementIndentStack->empty() + || inStatementIndentStack->back() == 0) + { + inStatementIndentStack->push_back(indentLength); + isInStatement = true; + } + } + // set indent for last definition line + else if (!lineBeginsWithOpenBracket) + { + if (shouldAlignMethodColon) + spaceIndentCount = computeObjCColonAlignment(line, colonIndentObjCMethodDefinition); + else if (inStatementIndentStack->empty()) + spaceIndentCount = spaceIndentObjCMethodDefinition; + } + } + + if (isInDefine) + { + if (line.length() > 0 && line[0] == '#') + { + // the 'define' does not have to be attached to the '#' + string preproc = trim(line.substr(1)); + if (preproc.compare(0, 6, "define") == 0) + { + if (!inStatementIndentStack->empty() + && inStatementIndentStack->back() > 0) + { + defineIndentCount = indentCount; + } + else + { + defineIndentCount = indentCount - 1; + indentCount--; + } + } + } + + indentCount -= defineIndentCount; + } + + if (indentCount < 0) + indentCount = 0; + + if (lineCommentNoBeautify || blockCommentNoBeautify || isInQuoteContinuation) + indentCount = spaceIndentCount = 0; + + // finally, insert indentations into begining of line + + string outBuffer = preLineWS(indentCount, spaceIndentCount) + line; + + prevFinalLineSpaceIndentCount = spaceIndentCount; + prevFinalLineIndentCount = indentCount; + + if (lastLineHeader != NULL) + previousLastLineHeader = lastLineHeader; + + return outBuffer; +} + + +string ASBeautifier::preLineWS(int lineIndentCount, int lineSpaceIndentCount) const +{ + if (shouldForceTabIndentation) + { + if (tabLength != indentLength) + { + // adjust for different tab length + int indentCountOrig = lineIndentCount; + int spaceIndentCountOrig = lineSpaceIndentCount; + lineIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) / tabLength; + lineSpaceIndentCount = ((indentCountOrig * indentLength) + spaceIndentCountOrig) % tabLength; + } + else + { + lineIndentCount += lineSpaceIndentCount / indentLength; + lineSpaceIndentCount = lineSpaceIndentCount % indentLength; + } + } + + string ws; + for (int i = 0; i < lineIndentCount; i++) + ws += indentString; + while ((lineSpaceIndentCount--) > 0) + ws += string(" "); + return ws; +} + +/** + * register an in-statement indent. + */ +void ASBeautifier::registerInStatementIndent(const string &line, int i, int spaceTabCount_, + int tabIncrementIn, int minIndent, bool updateParenStack) +{ + int inStatementIndent; + int remainingCharNum = line.length() - i; + int nextNonWSChar = getNextProgramCharDistance(line, i); + + // if indent is around the last char in the line, indent instead one indent from the previous indent + if (nextNonWSChar == remainingCharNum) + { + int previousIndent = spaceTabCount_; + if (!inStatementIndentStack->empty()) + previousIndent = inStatementIndentStack->back(); + int currIndent = /*2*/ indentLength + previousIndent; + if (currIndent > maxInStatementIndent + && line[i] != '{') + currIndent = indentLength * 2 + spaceTabCount_; + inStatementIndentStack->push_back(currIndent); + if (updateParenStack) + parenIndentStack->push_back(previousIndent); + return; + } + + if (updateParenStack) + parenIndentStack->push_back(i + spaceTabCount_ - horstmannIndentInStatement); + + int tabIncrement = tabIncrementIn; + + // check for following tabs + for (int j = i + 1; j < (i + nextNonWSChar); j++) + { + if (line[j] == '\t') + tabIncrement += convertTabToSpaces(j, tabIncrement); + } + + inStatementIndent = i + nextNonWSChar + spaceTabCount_ + tabIncrement; + + // check for run-in statement + if (i > 0 && line[0] == '{') + inStatementIndent -= indentLength; + + if (inStatementIndent < minIndent) + inStatementIndent = minIndent + spaceTabCount_; + + // this is not done for an in-statement array + if (inStatementIndent > maxInStatementIndent + && !(prevNonLegalCh == '=' && currentNonLegalCh == '{')) + inStatementIndent = indentLength * 2 + spaceTabCount_; + + if (!inStatementIndentStack->empty() && + inStatementIndent < inStatementIndentStack->back()) + inStatementIndent = inStatementIndentStack->back(); + + // the block opener is not indented for a NonInStatementArray + if (isNonInStatementArray && !isInEnum && !bracketBlockStateStack->empty() && bracketBlockStateStack->back()) + inStatementIndent = 0; + + inStatementIndentStack->push_back(inStatementIndent); +} + +/** + * Compute indentation for a preprocessor #if statement. + * This may be called for the activeBeautiferStack + * instead of the active ASBeautifier object. + */ +pair<int, int> ASBeautifier::computePreprocessorIndent() +{ + computePreliminaryIndentation(); + pair<int, int> entry (indentCount, spaceIndentCount); + if (!headerStack->empty() + && entry.first > 0 + && (headerStack->back() == &AS_IF + || headerStack->back() == &AS_ELSE + || headerStack->back() == &AS_FOR + || headerStack->back() == &AS_WHILE)) + --entry.first; + return entry; +} + +/** + * get distance to the next non-white space, non-comment character in the line. + * if no such character exists, return the length remaining to the end of the line. + */ +int ASBeautifier::getNextProgramCharDistance(const string &line, int i) const +{ + bool inComment = false; + int remainingCharNum = line.length() - i; + int charDistance; + char ch; + + for (charDistance = 1; charDistance < remainingCharNum; charDistance++) + { + ch = line[i + charDistance]; + if (inComment) + { + if (line.compare(i + charDistance, 2, "*/") == 0) + { + charDistance++; + inComment = false; + } + continue; + } + else if (isWhiteSpace(ch)) + continue; + else if (ch == '/') + { + if (line.compare(i + charDistance, 2, "//") == 0) + return remainingCharNum; + else if (line.compare(i + charDistance, 2, "/*") == 0) + { + charDistance++; + inComment = true; + } + } + else + return charDistance; + } + + return charDistance; +} + +// check if a specific line position contains a header. +const string* ASBeautifier::findHeader(const string &line, int i, + const vector<const string*>* possibleHeaders) const +{ + assert(isCharPotentialHeader(line, i)); + // check the word + size_t maxHeaders = possibleHeaders->size(); + for (size_t p = 0; p < maxHeaders; p++) + { + const string* header = (*possibleHeaders)[p]; + const size_t wordEnd = i + header->length(); + if (wordEnd > line.length()) + continue; + int result = (line.compare(i, header->length(), *header)); + if (result > 0) + continue; + if (result < 0) + break; + // check that this is not part of a longer word + if (wordEnd == line.length()) + return header; + if (isLegalNameChar(line[wordEnd])) + continue; + const char peekChar = peekNextChar(line, wordEnd - 1); + // is not a header if part of a definition + if (peekChar == ',' || peekChar == ')') + break; + // the following accessor definitions are NOT headers + // goto default; is NOT a header + // default(int) keyword in C# is NOT a header + else if ((header == &AS_GET || header == &AS_SET || header == &AS_DEFAULT) + && (peekChar == ';' || peekChar == '(' || peekChar == '=')) + break; + return header; + } + return NULL; +} + +// check if a specific line position contains an operator. +const string* ASBeautifier::findOperator(const string &line, int i, + const vector<const string*>* possibleOperators) const +{ + assert(isCharPotentialOperator(line[i])); + // find the operator in the vector + // the vector contains the LONGEST operators first + // must loop thru the entire vector + size_t maxOperators = possibleOperators->size(); + for (size_t p = 0; p < maxOperators; p++) + { + const size_t wordEnd = i + (*(*possibleOperators)[p]).length(); + if (wordEnd > line.length()) + continue; + if (line.compare(i, (*(*possibleOperators)[p]).length(), *(*possibleOperators)[p]) == 0) + return (*possibleOperators)[p]; + } + return NULL; +} + +/** + * find the index number of a string element in a container of strings + * + * @return the index number of element in the container. -1 if element not found. + * @param container a vector of strings. + * @param element the element to find . + */ +int ASBeautifier::indexOf(vector<const string*> &container, const string* element) const +{ + vector<const string*>::const_iterator where; + + where = find(container.begin(), container.end(), element); + if (where == container.end()) + return -1; + else + return (int) (where - container.begin()); +} + +/** + * convert tabs to spaces. + * i is the position of the character to convert to spaces. + * tabIncrementIn is the increment that must be added for tab indent characters + * to get the correct column for the current tab. + */ +int ASBeautifier::convertTabToSpaces(int i, int tabIncrementIn) const +{ + int tabToSpacesAdjustment = indentLength - 1 - ((tabIncrementIn + i) % indentLength); + return tabToSpacesAdjustment; +} + +/** + * trim removes the white space surrounding a line. + * + * @return the trimmed line. + * @param str the line to trim. + */ +string ASBeautifier::trim(const string &str) const +{ + + int start = 0; + int end = str.length() - 1; + + while (start < end && isWhiteSpace(str[start])) + start++; + + while (start <= end && isWhiteSpace(str[end])) + end--; + + // don't trim if it ends in a continuation + if (end > -1 && str[end] == '\\') + end = str.length() - 1; + + string returnStr(str, start, end + 1 - start); + return returnStr; +} + +/** + * rtrim removes the white space from the end of a line. + * + * @return the trimmed line. + * @param str the line to trim. + */ +string ASBeautifier::rtrim(const string &str) const +{ + size_t len = str.length(); + size_t end = str.find_last_not_of(" \t"); + if (end == string::npos + || end == len - 1) + return str; + string returnStr(str, 0, end + 1); + return returnStr; +} + +/** + * Copy tempStacks for the copy constructor. + * The value of the vectors must also be copied. + */ +vector<vector<const string*>*>* ASBeautifier::copyTempStacks(const ASBeautifier &other) const +{ + vector<vector<const string*>*>* tempStacksNew = new vector<vector<const string*>*>; + vector<vector<const string*>*>::iterator iter; + for (iter = other.tempStacks->begin(); + iter != other.tempStacks->end(); + ++iter) + { + vector<const string*>* newVec = new vector<const string*>; + *newVec = **iter; + tempStacksNew->push_back(newVec); + } + return tempStacksNew; +} + +/** + * delete a member vectors to eliminate memory leak reporting + */ +void ASBeautifier::deleteBeautifierVectors() +{ + beautifierFileType = 9; // reset to an invalid type + delete headers; + delete nonParenHeaders; + delete preBlockStatements; + delete preCommandHeaders; + delete assignmentOperators; + delete nonAssignmentOperators; + delete indentableHeaders; +} + +/** + * delete a vector object + * T is the type of vector + * used for all vectors except tempStacks + */ +template<typename T> +void ASBeautifier::deleteContainer(T &container) +{ + if (container != NULL) + { + container->clear(); + delete (container); + container = NULL; + } +} + +/** + * Delete the ASBeautifier vector object. + * This is a vector of pointers to ASBeautifier objects allocated with + * the 'new' operator. + * Therefore the ASBeautifier objects have to be deleted in addition to the + * ASBeautifier pointer entries. + */ +void ASBeautifier::deleteBeautifierContainer(vector<ASBeautifier*>* &container) +{ + if (container != NULL) + { + vector<ASBeautifier*>::iterator iter = container->begin(); + while (iter < container->end()) + { + delete *iter; + ++iter; + } + container->clear(); + delete (container); + container = NULL; + } +} + +/** + * Delete the tempStacks vector object. + * The tempStacks is a vector of pointers to strings allocated with + * the 'new' operator. + * Therefore the strings have to be deleted in addition to the + * tempStacks entries. + */ +void ASBeautifier::deleteTempStacksContainer(vector<vector<const string*>*>* &container) +{ + if (container != NULL) + { + vector<vector<const string*>*>::iterator iter = container->begin(); + while (iter < container->end()) + { + delete *iter; + ++iter; + } + container->clear(); + delete (container); + container = NULL; + } +} + +/** + * initialize a vector object + * T is the type of vector + * used for all vectors + */ +template<typename T> +void ASBeautifier::initContainer(T &container, T value) +{ + // since the ASFormatter object is never deleted, + // the existing vectors must be deleted before creating new ones + if (container != NULL ) + deleteContainer(container); + container = value; +} + +/** + * Determine if an assignment statement ends with a comma + * that is not in a function argument. It ends with a + * comma if a comma is the last char on the line. + * + * @return true if line ends with a comma, otherwise false. + */ +bool ASBeautifier::statementEndsWithComma(const string &line, int index) const +{ + assert(line[index] == '='); + + bool isInComment_ = false; + bool isInQuote_ = false; + int parenCount = 0; + size_t lineLength = line.length(); + size_t i = 0; + char quoteChar_ = ' '; + + for (i = index + 1; i < lineLength; ++i) + { + char ch = line[i]; + + if (isInComment_) + { + if (line.compare(i, 2, "*/") == 0) + { + isInComment_ = false; + ++i; + } + continue; + } + + if (ch == '\\') + { + ++i; + continue; + } + + if (isInQuote_) + { + if (ch == quoteChar_) + isInQuote_ = false; + continue; + } + + if (ch == '"' || ch == '\'') + { + isInQuote_ = true; + quoteChar_ = ch; + continue; + } + + if (line.compare(i, 2, "//") == 0) + break; + + if (line.compare(i, 2, "/*") == 0) + { + if (isLineEndComment(line, i)) + break; + else + { + isInComment_ = true; + ++i; + continue; + } + } + + if (ch == '(') + parenCount++; + if (ch == ')') + parenCount--; + } + if (isInComment_ + || isInQuote_ + || parenCount > 0) + return false; + + size_t lastChar = line.find_last_not_of(" \t", i - 1); + + if (lastChar == string::npos || line[lastChar] != ',') + return false; + + return true; +} + +/** + * check if current comment is a line-end comment + * + * @return is before a line-end comment. + */ +bool ASBeautifier::isLineEndComment(const string &line, int startPos) const +{ + assert(line.compare(startPos, 2, "/*") == 0); + + // comment must be closed on this line with nothing after it + size_t endNum = line.find("*/", startPos + 2); + if (endNum != string::npos) + { + size_t nextChar = line.find_first_not_of(" \t", endNum + 2); + if (nextChar == string::npos) + return true; + } + return false; +} + +/** + * get the previous word index for an assignment operator + * + * @return is the index to the previous word (the in statement indent). + */ +int ASBeautifier::getInStatementIndentAssign(const string &line, size_t currPos) const +{ + assert(line[currPos] == '='); + + if (currPos == 0) + return 0; + + // get the last legal word (may be a number) + size_t end = line.find_last_not_of(" \t", currPos - 1); + if (end == string::npos || !isLegalNameChar(line[end])) + return 0; + + int start; // start of the previous word + for (start = end; start > -1; start--) + { + if (!isLegalNameChar(line[start]) || line[start] == '.') + break; + } + start++; + + return start; +} + +/** + * get the instatement indent for a comma + * + * @return is the indent to the second word on the line (the in statement indent). + */ +int ASBeautifier::getInStatementIndentComma(const string &line, size_t currPos) const +{ + assert(line[currPos] == ','); + + // get first word on a line + size_t indent = line.find_first_not_of(" \t"); + if (indent == string::npos || !isLegalNameChar(line[indent])) + return 0; + + // bypass first word + for (; indent < currPos; indent++) + { + if (!isLegalNameChar(line[indent])) + break; + } + indent++; + if (indent >= currPos || indent < 4) + return 0; + + // point to second word or assignment operator + indent = line.find_first_not_of(" \t", indent); + if (indent == string::npos || indent >= currPos) + return 0; + + return indent; +} + +/** + * get the next word on a line + * the argument 'currPos' must point to the current position. + * + * @return is the next word or an empty string if none found. + */ +string ASBeautifier::getNextWord(const string &line, size_t currPos) const +{ + size_t lineLength = line.length(); + // get the last legal word (may be a number) + if (currPos == lineLength - 1) + return string(); + + size_t start = line.find_first_not_of(" \t", currPos + 1); + if (start == string::npos || !isLegalNameChar(line[start])) + return string(); + + size_t end; // end of the current word + for (end = start + 1; end <= lineLength; end++) + { + if (!isLegalNameChar(line[end]) || line[end] == '.') + break; + } + + return line.substr(start, end - start); +} + +/** + * Check if a preprocessor directive is always indented. + * C# "region... [truncated message content] |