Use an internal version of astyle (astyle 3.0). Scripts taken from QGIS.
astyle.options from https://github.com/uclouvain/openjpeg/issues/128
scripts/prepare-commit.sh can be used locally to automatically reformat
edited files.
Travis-CI will run scripts/verify-indentation.sh to verify committed files.
/src/bin/common/opj_apps_config.h
/src/lib/openjp2/opj_config.h
/src/lib/openjp2/opj_config_private.h
+scripts/opjstyle*
# Ignore directories made by `make`.
/bin/
-language: c
+language: cpp
matrix:
include:
compiler: clang
env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release OPJ_CI_INCLUDE_IF_DEPLOY=1
- os: linux
- compiler: gcc
+ compiler: clang-3.8
+ env: OPJ_CI_CC=clang-3.8 OPJ_CI_CXX=clang-3.8 OPJ_CI_CHECK_STYLE=1 OPJ_CI_SKIP_TESTS=1
+ addons:
+ apt:
+ sources:
+ - llvm-toolchain-precise-3.8
+ - ubuntu-toolchain-r-test
+ packages:
+ - clang-3.8
+ - flip
+ - os: linux
+ compiler: g++
env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release OPJ_CI_INCLUDE_IF_DEPLOY=1 OPJ_CI_PERF_TESTS=1
- os: linux
- compiler: gcc
+ compiler: g++
env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release OPJ_NUM_THREADS=2
- os: linux
- compiler: gcc
+ compiler: g++
env: OPJ_CI_ARCH=i386 OPJ_CI_BUILD_CONFIGURATION=Release
addons:
apt:
packages:
- gcc-multilib
+ - g++-multilib
- os: linux
- compiler: gcc
+ compiler: g++
env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Debug OPJ_CI_PROFILE=1
addons:
apt:
env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Debug OPJ_CI_ASAN=1
- os: linux
compiler: clang-3.8
- env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release OPJ_CI_PERF_TESTS=1
+ env: OPJ_CI_CC=clang-3.8 OPJ_CI_CXX=clang-3.8 OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release OPJ_CI_PERF_TESTS=1
addons:
apt:
sources:
packages:
- clang-3.8
- os: linux
- compiler: x86_64-w64-mingw32-gcc
- env: OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release
+ compiler: x86_64-w64-mingw32-g++
+ env: OPJ_CI_CC=x86_64-w64-mingw32-gcc OPJ_CI_CXX=x86_64-w64-mingw32-g++ OPJ_CI_ARCH=i386 OPJ_CI_BUILD_CONFIGURATION=Release
addons:
apt:
packages:
- gcc-mingw-w64-base
- - binutils-mingw-w64-x86-64
- - gcc-mingw-w64-x86-64
- - gcc-mingw-w64
+ - binutils-mingw-w64-i686
+ - gcc-mingw-w64-i686
+ - gcc-mingw-w64
+ - g++-mingw-w64-i686
+ - gcc-multilib
+ - g++-multilib
- os: linux
- compiler: x86_64-w64-mingw32-gcc
- env: OPJ_CI_ARCH=i386 OPJ_CI_BUILD_CONFIGURATION=Release
+ compiler: x86_64-w64-mingw32-g++
+ env: OPJ_CI_CC=x86_64-w64-mingw32-gcc OPJ_CI_CXX=x86_64-w64-mingw32-g++ OPJ_CI_ARCH=x86_64 OPJ_CI_BUILD_CONFIGURATION=Release
addons:
apt:
packages:
- gcc-mingw-w64-base
- - binutils-mingw-w64-i686
- - gcc-mingw-w64-i686
- - gcc-mingw-w64
+ - binutils-mingw-w64-x86-64
+ - gcc-mingw-w64-x86-64
+ - gcc-mingw-w64
+ - g++-mingw-w64-x86-64
- os: linux
- compiler: gcc-4.8
- env: OPJ_CI_ABI_CHECK=1
+ compiler: g++-4.8
+ env: OPJ_CI_CC=gcc-4.8 OPJ_CI_CXX=g++-4.8 OPJ_CI_ABI_CHECK=1
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- gcc-4.8
+ - g++-4.8
- libelf-dev
- elfutils
- texinfo
#string(TOLOWER ${OPENJPEG_NAMESPACE} OPENJPEG_LIBRARY_NAME)
set(OPENJPEG_LIBRARY_NAME openjp2)
-project(${OPENJPEG_NAMESPACE} C)
+project(${OPENJPEG_NAMESPACE})
# Do full dependency headers.
include_regular_expression("^.*$")
endif()
#-----------------------------------------------------------------------------
+
+# build our version of astyle
+SET (WITH_ASTYLE FALSE CACHE BOOL "If you plan to contribute you should reindent with scripts/prepare-commit.sh (using 'our' astyle)")
* To build the shared libraries and links the executables against it: '-DBUILD\_SHARED\_LIBS:bool=on' (default: 'ON')
> Note: when using this option, static libraries are not built and executables are dynamically linked.
* To build the CODEC executables: '-DBUILD\_CODEC:bool=on' (default: 'ON')
+ * To build opjstyle (internal version of astyle) for OpenJPEG development: '-DWITH_ASTYLE=ON'
* [OBSOLETE] To build the MJ2 executables: '-DBUILD\_MJ2:bool=on' (default: 'OFF')
* [OBSOLETE] To build the JPWL executables and JPWL library: '-DBUILD\_JPWL:bool=on' (default: 'OFF')
* [OBSOLETE] To build the JPIP client (java compiler recommended) library and executables: '-DBUILD\_JPIP:bool=on' (default: 'OFF')
You can use cmake to generate the project files for the IDE you are using (VC2010, XCode, etc).
Type 'cmake --help' for available generators on your platform.
+# Modifying OpenJPEG
+
+Before committing changes, run:
+scripts/prepare-commit.sh
+
# Using OpenJPEG
To use openjpeg exported cmake file, simply create your application doing:
* doc: doxygen documentation setup file and man pages
* tests: configuration files and utilities for the openjpeg test suite. All test images are located in [openjpeg-data](https://github.com/uclouvain/openjpeg-data) repository.
* cmake: cmake related files
+* scripts: scripts for developers
See [LICENSE][link-license] for license and copyright information.
--- /dev/null
+--convert-tabs
+--lineend=linux
+--indent=spaces=4
+--style=kr
+--add-brackets
+--max-code-length=80
+--break-after-logical
+--pad-header
+--pad-oper
+--unpad-paren
+--suffix=none
--- /dev/null
+#!/bin/bash
+###########################################################################
+# astyle.sh
+# ---------------------
+# Date : August 2008
+# Copyright : (C) 2008 by Juergen E. Fischer
+# Email : jef at norbit dot de
+###########################################################################
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation; either version 2 of the License, or #
+# (at your option) any later version. #
+# #
+###########################################################################
+
+for ASTYLE in ${OPJSTYLE} $(dirname $0)/opjstyle $(dirname $0)/RelWithDebInfo/opjstyle
+do
+ if type -p $ASTYLE >/dev/null; then
+ break
+ fi
+ ASTYLE=
+done
+
+if [ -z "$ASTYLE" ]; then
+ echo "opjstyle not found - please enable WITH_ASTYLE in cmake and build it" >&2
+ exit 1
+fi
+
+if type -p tput >/dev/null; then
+ elcr="$ASTYLEPROGRESS$(tput el)$(tput cr)"
+else
+ elcr="$ASTYLEPROGRESS \r"
+fi
+
+if ! type -p flip >/dev/null; then
+ if type -p dos2unix >/dev/null; then
+ flip() {
+ dos2unix -k $2
+ }
+ else
+ echo "flip not found" >&2
+ flip() {
+ :
+ }
+ fi
+fi
+
+if ! type -p autopep8 >/dev/null; then
+ echo "autopep8 not found" >&2
+ autopep8() {
+ :
+ }
+fi
+
+ASTYLEOPTS=$(dirname $0)/astyle.options
+if type -p cygpath >/dev/null; then
+ ASTYLEOPTS="$(cygpath -w $ASTYLEOPTS)"
+fi
+
+set -e
+
+astyleit() {
+ $ASTYLE --options="$ASTYLEOPTS" "$1"
+ #modified=$1.unify_includes_modified
+ #cp "$1" "$modified"
+ #scripts/unify_includes.pl "$modified"
+ #scripts/doxygen_space.pl "$modified"
+ #diff "$1" "$modified" >/dev/null || mv "$modified" "$1"
+ #rm -f "$modified"
+}
+
+for f in "$@"; do
+ case "$f" in
+ thirdparty/*)
+ echo -ne "$f skipped $elcr"
+ continue
+ ;;
+
+ *.cpp|*.h|*.c|*.h|*.cxx|*.hxx|*.c++|*.h++|*.cc|*.hh|*.C|*.H|*.hpp)
+ if [ -x "$f" ]; then
+ chmod a-x "$f"
+ fi
+ cmd=astyleit
+ ;;
+
+ *.py)
+ #cmd="autopep8 --in-place --ignore=E111,E128,E201,E202,E203,E211,E221,E222,E225,E226,E227,E231,E241,E261,E265,E272,E302,E303,E501,E701"
+ echo -ne "Formatting $f $elcr"
+ cmd="autopep8 --in-place --ignore=E261,E265,E402,E501"
+ ;;
+
+
+ *)
+ echo -ne "$f skipped $elcr"
+ continue
+ ;;
+ esac
+
+ if ! [ -f "$f" ]; then
+ echo "$f not found" >&2
+ continue
+ fi
+
+ if [[ -f $f && `head -c 3 $f` == $'\xef\xbb\xbf' ]]; then
+ mv $f $f.bom
+ tail -c +4 $f.bom > $f
+ echo "removed BOM from $f"
+ fi
+
+ modified=$f.flip_modified
+ cp "$f" "$modified"
+ flip -ub "$modified"
+ diff "$f" "$modified" >/dev/null || mv "$modified" "$f"
+ rm -f "$modified"
+ eval "$cmd '$f'"
+done
--- /dev/null
+#!/usr/bin/env bash
+###########################################################################
+# prepare-commit.sh
+# ---------------------
+# Date : August 2008
+# Copyright : (C) 2008 by Juergen E. Fischer
+# Email : jef at norbit dot de
+###########################################################################
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation; either version 2 of the License, or #
+# (at your option) any later version. #
+# #
+###########################################################################
+
+TOPLEVEL=$(git rev-parse --show-toplevel)
+
+PATH=$TOPLEVEL/scripts:$PATH
+
+cd $TOPLEVEL
+
+# GNU prefix command for mac os support (gsed, gsplit)
+GP=
+if [[ "$OSTYPE" =~ darwin* ]]; then
+ GP=g
+fi
+
+if ! type -p astyle.sh >/dev/null; then
+ echo astyle.sh not found
+ exit 1
+fi
+
+if ! type -p colordiff >/dev/null; then
+ colordiff()
+ {
+ cat "$@"
+ }
+fi
+
+if [ "$1" = "-c" ]; then
+ echo "Cleaning..."
+ remove_temporary_files.sh
+fi
+
+set -e
+
+# determine changed files
+MODIFIED=$(git status --porcelain| ${GP}sed -ne "s/^ *[MA] *//p" | sort -u)
+#MODIFIED=$(find src -name "*.c")
+
+if [ -z "$MODIFIED" ]; then
+ echo nothing was modified
+ exit 0
+fi
+
+# save original changes
+REV=$(git log -n1 --pretty=%H)
+git diff >sha-$REV.diff
+
+ASTYLEDIFF=astyle.$REV.diff
+>$ASTYLEDIFF
+
+# reformat
+i=0
+N=$(echo $MODIFIED | wc -w)
+for f in $MODIFIED; do
+ (( i++ )) || true
+
+ case "$f" in
+ thirdparty/*)
+ echo $f skipped
+ continue
+ ;;
+
+ *.cpp|*.c|*.h|*.cxx|*.hxx|*.c++|*.h++|*.cc|*.hh|*.C|*.H|*.sip|*.py)
+ ;;
+
+ *)
+ continue
+ ;;
+ esac
+
+ m=$f.$REV.prepare
+
+ cp $f $m
+ ASTYLEPROGRESS=" [$i/$N]" astyle.sh $f
+ if diff -u $m $f >>$ASTYLEDIFF; then
+ # no difference found
+ rm $m
+ fi
+done
+
+if [ -s "$ASTYLEDIFF" ]; then
+ if tty -s; then
+ # review astyle changes
+ colordiff <$ASTYLEDIFF | less -r
+ else
+ echo "Files changed (see $ASTYLEDIFF)"
+ fi
+ exit 1
+else
+ rm $ASTYLEDIFF
+fi
+
+
+# If there are whitespace errors, print the offending file names and fail.
+exec git diff-index --check --cached HEAD --
+
+exit 0
+
+# vim: set ts=8 noexpandtab :
--- /dev/null
+#!/bin/bash
+###########################################################################
+# remove_git_confict_files.sh
+# ---------------------
+# Date : April 2012
+# Copyright : (C) 2012 by Tim Sutton
+# Email : tim at kartoza dot com
+###########################################################################
+# #
+# This program is free software; you can redistribute it and/or modify #
+# it under the terms of the GNU General Public License as published by #
+# the Free Software Foundation; either version 2 of the License, or #
+# (at your option) any later version. #
+# #
+###########################################################################
+
+#
+# A simple script to get rid of QGIS related temporary files left in
+# your QGIS source folder by git
+
+# Tim Sutton, May 2008
+find . \
+ \( \
+ -name "*.orig" \
+ -o -name "*.prepare" \
+ -o -name "*.sortinc" \
+ -o -name "*.unify_includes_modified" \
+ -o -name "*.nocopyright" \
+ -o -name "astyle*.diff" \
+ -o -name "sha-*.diff" \
+ -o -name "*.astyle" \
+ -o -name "sha*.diff" \
+ -o -name "*.bom" \
+ -o -name "*.bak" \
+ -o -name "*.rej" \
+ -o -name "*.orig" \
+ -o -name "*.new" \
+ -o -name "*~" \
+ \) \
+ -print \
+ -delete
--- /dev/null
+#!/bin/bash
+cd $(git rev-parse --show-toplevel)
+
+export PATH=$PATH:$PWD/scripts
+
+if [ -z "$TRAVIS_COMMIT_RANGE" ]; then
+ echo "No commit range given"
+ exit 0
+fi
+
+if ! type -p astyle.sh >/dev/null; then
+ echo astyle.sh not found
+ exit 1
+fi
+
+set -e
+
+ASTYLEDIFF=/tmp/astyle.diff
+>$ASTYLEDIFF
+
+
+if [[ ! -z $TRAVIS_PULL_REQUEST_BRANCH ]]; then
+ # if on a PR, just analyse the changed files
+ echo "TRAVIS PR BRANCH: $TRAVIS_PULL_REQUEST_BRANCH"
+ FILES=$(git diff --diff-filter=AM --name-only $(git merge-base HEAD master) | tr '\n' ' ' )
+elif [[ ! -z $TRAVIS_COMMIT_RANGE ]]; then
+ echo "TRAVIS COMMIT RANGE: $TRAVIS_COMMIT_RANGE"
+ FILES=$(git diff --diff-filter=AM --name-only ${TRAVIS_COMMIT_RANGE/.../..} | tr '\n' ' ' )
+fi
+
+for f in $FILES; do
+ if ! [ -f "$f" ]; then
+ echo "$f was removed." >>/tmp/ctest-important.log
+ continue
+ fi
+
+ echo "Checking $f" >>/tmp/ctest-important.log
+ case "$f" in
+ thirdparty*)
+ echo "$f skipped"
+ continue
+ ;;
+
+ *.cpp|*.c|*.h|*.cxx|*.hxx|*.c++|*.h++|*.cc|*.hh|*.C|*.H|*.sip|*.py)
+ ;;
+
+ *)
+ continue
+ ;;
+ esac
+
+ m="$f.prepare"
+ cp "$f" "$m"
+ astyle.sh "$f"
+ if diff -u "$m" "$f" >>$ASTYLEDIFF; then
+ rm "$m"
+ else
+ echo "File $f needs indentation"
+ fi
+done
+
+if [ -s "$ASTYLEDIFF" ]; then
+ echo
+ echo "Required indentation updates:"
+ cat "$ASTYLEDIFF"
+
+ cat <<EOF
+
+Tips to prevent and resolve:
+* Enable WITH_ASTYLE in your cmake configuration to format C++ code
+* Install autopep8 (>= 1.2.1) to format python code
+* Use "scripts/astyle.sh file" to fix the now badly indented files
+* Consider using scripts/prepare-commit.sh as pre-commit hook to avoid this
+ in the future (ln -s scripts/prepare-commit.sh .git/hooks/pre-commit) or
+ run it manually before each commit.
+EOF
+
+ exit 1
+fi
endif(LCMS_FOUND)
endif(LCMS2_FOUND)
endif(BUILD_THIRDPARTY)
+
+
+#------------
+IF (WITH_ASTYLE)
+ ADD_SUBDIRECTORY(astyle)
+ENDIF(WITH_ASTYLE)
--- /dev/null
+// ASBeautifier.cpp
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+
+//-----------------------------------------------------------------------------
+// headers
+//-----------------------------------------------------------------------------
+
+#include "astyle.h"
+
+#include <algorithm>
+
+//-----------------------------------------------------------------------------
+// astyle namespace
+//-----------------------------------------------------------------------------
+
+namespace astyle {
+//
+// this must be global
+static int g_preprocessorCppExternCBrace;
+
+//-----------------------------------------------------------------------------
+// ASBeautifier class
+//-----------------------------------------------------------------------------
+
+/**
+ * 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()
+{
+ waitingBeautifierStack = nullptr;
+ activeBeautifierStack = nullptr;
+ waitingBeautifierStackLengthStack = nullptr;
+ activeBeautifierStackLengthStack = nullptr;
+
+ headerStack = nullptr;
+ tempStacks = nullptr;
+ squareBracketDepthStack = nullptr;
+ blockStatementStack = nullptr;
+ parenStatementStack = nullptr;
+ braceBlockStateStack = nullptr;
+ continuationIndentStack = nullptr;
+ continuationIndentStackSizeStack = nullptr;
+ parenIndentStack = nullptr;
+ preprocIndentStack = nullptr;
+ sourceIterator = nullptr;
+ isModeManuallySet = false;
+ shouldForceTabIndentation = false;
+ setSpaceIndentation(4);
+ setContinuationIndentation(1);
+ setMinConditionalIndentOption(MINCOND_TWO);
+ setMaxContinuationIndentLength(40);
+ classInitializerIndents = 1;
+ tabLength = 0;
+ setClassIndent(false);
+ setModifierIndent(false);
+ setSwitchIndent(false);
+ setCaseIndent(false);
+ setBlockIndent(false);
+ setBraceIndent(false);
+ setBraceIndentVtk(false);
+ setNamespaceIndent(false);
+ setAfterParenIndent(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 = nullptr;
+ activeBeautifierStack = nullptr;
+ waitingBeautifierStackLengthStack = nullptr;
+ activeBeautifierStackLengthStack = nullptr;
+
+ // vector '=' operator performs a DEEP copy of all elements in the vector
+
+ headerStack = new vector<const string*>;
+ *headerStack = *other.headerStack;
+
+ tempStacks = copyTempStacks(other);
+
+ squareBracketDepthStack = new vector<int>;
+ *squareBracketDepthStack = *other.squareBracketDepthStack;
+
+ blockStatementStack = new vector<bool>;
+ *blockStatementStack = *other.blockStatementStack;
+
+ parenStatementStack = new vector<bool>;
+ *parenStatementStack = *other.parenStatementStack;
+
+ braceBlockStateStack = new vector<bool>;
+ *braceBlockStateStack = *other.braceBlockStateStack;
+
+ continuationIndentStack = new vector<int>;
+ *continuationIndentStack = *other.continuationIndentStack;
+
+ continuationIndentStackSizeStack = new vector<int>;
+ *continuationIndentStackSizeStack = *other.continuationIndentStackSizeStack;
+
+ 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;
+ runInIndentContinuation = other.runInIndentContinuation;
+ nonInStatementBrace = other.nonInStatementBrace;
+ objCColonAlignSubsequent = other.objCColonAlignSubsequent;
+ 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;
+ isInIndentablePreproc = other.isInIndentablePreproc;
+
+ // 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;
+ isInRunInComment = other.isInRunInComment;
+ isInCase = other.isInCase;
+ isInQuestion = other.isInQuestion;
+ isContinuation = other.isContinuation;
+ isInHeader = other.isInHeader;
+ isInTemplate = other.isInTemplate;
+ isInDefine = other.isInDefine;
+ isInDefineDefinition = other.isInDefineDefinition;
+ classIndent = other.classIndent;
+ isIndentModeOff = other.isIndentModeOff;
+ isInClassHeader = other.isInClassHeader;
+ isInClassHeaderTab = other.isInClassHeaderTab;
+ isInClassInitializer = other.isInClassInitializer;
+ isInClass = other.isInClass;
+ isInObjCMethodDefinition = other.isInObjCMethodDefinition;
+ isInObjCMethodCall = other.isInObjCMethodCall;
+ isInObjCMethodCallFirst = other.isInObjCMethodCallFirst;
+ isImmediatelyPostObjCMethodDefinition = other.isImmediatelyPostObjCMethodDefinition;
+ isImmediatelyPostObjCMethodCall = other.isImmediatelyPostObjCMethodCall;
+ isInIndentablePreprocBlock = other.isInIndentablePreprocBlock;
+ isInObjCInterface = other.isInObjCInterface;
+ isInEnum = other.isInEnum;
+ isInEnumTypeID = other.isInEnumTypeID;
+ isInLet = other.isInLet;
+ modifierIndent = other.modifierIndent;
+ switchIndent = other.switchIndent;
+ caseIndent = other.caseIndent;
+ namespaceIndent = other.namespaceIndent;
+ braceIndent = other.braceIndent;
+ braceIndentVtk = other.braceIndentVtk;
+ blockIndent = other.blockIndent;
+ shouldIndentAfterParen = other.shouldIndentAfterParen;
+ 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;
+ lineBeginsWithOpenBrace = other.lineBeginsWithOpenBrace;
+ lineBeginsWithCloseBrace = other.lineBeginsWithCloseBrace;
+ lineBeginsWithComma = other.lineBeginsWithComma;
+ lineIsCommentOnly = other.lineIsCommentOnly;
+ lineIsLineCommentOnly = other.lineIsLineCommentOnly;
+ shouldIndentBracedLine = other.shouldIndentBracedLine;
+ isInSwitch = other.isInSwitch;
+ foundPreCommandHeader = other.foundPreCommandHeader;
+ foundPreCommandMacro = other.foundPreCommandMacro;
+ shouldAlignMethodColon = other.shouldAlignMethodColon;
+ shouldIndentPreprocDefine = other.shouldIndentPreprocDefine;
+ shouldIndentPreprocConditional = other.shouldIndentPreprocConditional;
+ indentCount = other.indentCount;
+ spaceIndentCount = other.spaceIndentCount;
+ spaceIndentObjCMethodAlignment = other.spaceIndentObjCMethodAlignment;
+ bracePosObjCMethodAlignment = other.bracePosObjCMethodAlignment;
+ colonIndentObjCMethodAlignment = other.colonIndentObjCMethodAlignment;
+ lineOpeningBlocksNum = other.lineOpeningBlocksNum;
+ lineClosingBlocksNum = other.lineClosingBlocksNum;
+ fileType = other.fileType;
+ minConditionalOption = other.minConditionalOption;
+ minConditionalIndent = other.minConditionalIndent;
+ parenDepth = other.parenDepth;
+ indentLength = other.indentLength;
+ tabLength = other.tabLength;
+ continuationIndent = other.continuationIndent;
+ blockTabCount = other.blockTabCount;
+ maxContinuationIndent = other.maxContinuationIndent;
+ classInitializerIndents = other.classInitializerIndents;
+ templateDepth = other.templateDepth;
+ squareBracketCount = other.squareBracketCount;
+ prevFinalLineSpaceIndentCount = other.prevFinalLineSpaceIndentCount;
+ prevFinalLineIndentCount = other.prevFinalLineIndentCount;
+ defineIndentCount = other.defineIndentCount;
+ preprocBlockIndent = other.preprocBlockIndent;
+ 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(squareBracketDepthStack);
+ deleteContainer(blockStatementStack);
+ deleteContainer(parenStatementStack);
+ deleteContainer(braceBlockStateStack);
+ deleteContainer(continuationIndentStack);
+ deleteContainer(continuationIndentStackSizeStack);
+ 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() receives 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());
+ g_preprocessorCppExternCBrace = 0;
+
+ 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*>);
+
+ initTempStacksContainer(tempStacks, new vector<vector<const string*>*>);
+ tempStacks->emplace_back(new vector<const string*>);
+
+ initContainer(squareBracketDepthStack, new vector<int>);
+ initContainer(blockStatementStack, new vector<bool>);
+ initContainer(parenStatementStack, new vector<bool>);
+ initContainer(braceBlockStateStack, new vector<bool>);
+ braceBlockStateStack->push_back(true);
+ initContainer(continuationIndentStack, new vector<int>);
+ initContainer(continuationIndentStackSizeStack, new vector<int>);
+ continuationIndentStackSizeStack->emplace_back(0);
+ initContainer(parenIndentStack, new vector<int>);
+ initContainer(preprocIndentStack, new vector<pair<int, int> >);
+
+ previousLastLineHeader = nullptr;
+ currentHeader = nullptr;
+
+ isInQuote = false;
+ isInVerbatimQuote = false;
+ haveLineContinuationChar = false;
+ isInAsm = false;
+ isInAsmOneLine = false;
+ isInAsmBlock = false;
+ isInComment = false;
+ isInPreprocessorComment = false;
+ isInRunInComment = false;
+ isContinuation = false;
+ isInCase = false;
+ isInQuestion = false;
+ isIndentModeOff = false;
+ isInClassHeader = false;
+ isInClassHeaderTab = false;
+ isInClassInitializer = false;
+ isInClass = false;
+ isInObjCMethodDefinition = false;
+ isInObjCMethodCall = false;
+ isInObjCMethodCallFirst = false;
+ isImmediatelyPostObjCMethodDefinition = false;
+ isImmediatelyPostObjCMethodCall = false;
+ isInIndentablePreprocBlock = false;
+ isInObjCInterface = false;
+ isInEnum = false;
+ isInEnumTypeID = false;
+ isInLet = false;
+ isInHeader = false;
+ isInTemplate = false;
+ isInConditional = false;
+
+ indentCount = 0;
+ spaceIndentCount = 0;
+ spaceIndentObjCMethodAlignment = 0;
+ bracePosObjCMethodAlignment = 0;
+ colonIndentObjCMethodAlignment = 0;
+ lineOpeningBlocksNum = 0;
+ lineClosingBlocksNum = 0;
+ templateDepth = 0;
+ squareBracketCount = 0;
+ parenDepth = 0;
+ blockTabCount = 0;
+ prevFinalLineSpaceIndentCount = 0;
+ prevFinalLineIndentCount = 0;
+ defineIndentCount = 0;
+ preprocBlockIndent = 0;
+ prevNonSpaceCh = '{';
+ currentNonSpaceCh = '{';
+ prevNonLegalCh = '{';
+ currentNonLegalCh = '{';
+ quoteChar = ' ';
+ probationHeader = nullptr;
+ lastLineHeader = nullptr;
+ backslashEndsPrevLine = false;
+ lineOpensWithLineComment = false;
+ lineOpensWithComment = false;
+ lineStartsInComment = false;
+ isInDefine = false;
+ isInDefineDefinition = false;
+ lineCommentNoBeautify = false;
+ isElseHeaderIndent = false;
+ isCaseHeaderCommentIndent = false;
+ blockCommentNoIndent = false;
+ blockCommentNoBeautify = false;
+ previousLineProbationTab = false;
+ lineBeginsWithOpenBrace = false;
+ lineBeginsWithCloseBrace = false;
+ lineBeginsWithComma = false;
+ lineIsCommentOnly = false;
+ lineIsLineCommentOnly = false;
+ shouldIndentBracedLine = true;
+ isInSwitch = false;
+ foundPreCommandHeader = false;
+ foundPreCommandMacro = false;
+
+ isNonInStatementArray = false;
+ isSharpAccessor = false;
+ isSharpDelegate = false;
+ isInExternC = false;
+ isInBeautifySQL = false;
+ isInIndentableStruct = false;
+ isInIndentablePreproc = false;
+ inLineNumber = 0;
+ runInIndentContinuation = 0;
+ nonInStatementBrace = 0;
+ objCColonAlignSubsequent = 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 explicitly 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;
+}
+
+/**
+* indent continuation lines using a number of indents.
+*
+* @param indent number of indents per line.
+*/
+void ASBeautifier::setContinuationIndentation(int indent)
+{
+ continuationIndent = indent;
+}
+
+/**
+ * set the maximum indentation between two lines in a multi-line statement.
+ *
+ * @param max maximum indentation length.
+ */
+void ASBeautifier::setMaxContinuationIndentLength(int max)
+{
+ maxContinuationIndent = max;
+}
+
+// retained for compatability with release 2.06
+// "MaxInStatementIndent" has been changed to "MaxContinuationIndent" in 3.0
+// it is referenced only by the old "MaxInStatementIndent" options
+void ASBeautifier::setMaxInStatementIndentLength(int max)
+{
+ setMaxContinuationIndentLength(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 brace indent option. If true, braces will
+ * be indented one additional indent.
+ *
+ * @param state state of option.
+ */
+void ASBeautifier::setBraceIndent(bool state)
+{
+ braceIndent = state;
+}
+
+/**
+* set the state of the brace indent VTK option. If true, braces will
+* be indented one additional indent, except for the opening brace.
+*
+* @param state state of option.
+*/
+void ASBeautifier::setBraceIndentVtk(bool state)
+{
+ // need to set both of these
+ setBraceIndent(state);
+ braceIndentVtk = 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 modifier indentation option. If true, C++ class
+ * access modifiers will be indented one-half an indent.
+ *
+ * @param state state of option.
+ */
+void ASBeautifier::setModifierIndent(bool state)
+{
+ modifierIndent = 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 indent after parens option.
+*
+* @param state state of option.
+*/
+void ASBeautifier::setAfterParenIndent(bool state)
+{
+ shouldIndentAfterParen = 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, multi-line #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() const
+{
+ return indentLength;
+}
+
+/**
+ * get the char used for indentation, space or tab
+ *
+ * @return the char used for indentation.
+ */
+string ASBeautifier::getIndentString() 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() const
+{
+ return shouldForceTabIndentation;
+}
+
+/**
+* Get the state of the Objective-C align method colon option.
+*
+* @return state of shouldAlignMethodColon option.
+*/
+bool ASBeautifier::getAlignMethodColon() const
+{
+ return shouldAlignMethodColon;
+}
+
+/**
+ * get the state of the block indentation option.
+ *
+ * @return state of blockIndent option.
+ */
+bool ASBeautifier::getBlockIndent() const
+{
+ return blockIndent;
+}
+
+/**
+ * get the state of the brace indentation option.
+ *
+ * @return state of braceIndent option.
+ */
+bool ASBeautifier::getBraceIndent() const
+{
+ return braceIndent;
+}
+
+/**
+* Get the state of the namespace indentation option. If true, blocks
+* of the 'namespace' statement will be indented one additional indent.
+*
+* @return state of namespaceIndent option.
+*/
+bool ASBeautifier::getNamespaceIndent() const
+{
+ return namespaceIndent;
+}
+
+/**
+ * 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() const
+{
+ return classIndent;
+}
+
+/**
+ * Get the state of the class access modifier indentation option.
+ * If true, the class access modifiers will be indented one-half indent.
+ *
+ * @return state of modifierIndent option.
+ */
+bool ASBeautifier::getModifierIndent() const
+{
+ return modifierIndent;
+}
+
+/**
+ * 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() 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() 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() 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() const
+{
+ return shouldIndentPreprocDefine;
+}
+
+/**
+ * get the length of the tab indentation option.
+ *
+ * @return length of tab indent option.
+ */
+int ASBeautifier::getTabLength() 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 = nullptr;
+ lastLineHeader = nullptr;
+ blockCommentNoBeautify = blockCommentNoIndent;
+ isInClass = false;
+ isInSwitch = false;
+ lineBeginsWithOpenBrace = false;
+ lineBeginsWithCloseBrace = false;
+ lineBeginsWithComma = false;
+ lineIsCommentOnly = false;
+ lineIsLineCommentOnly = false;
+ shouldIndentBracedLine = true;
+ isInAsmOneLine = false;
+ lineOpensWithLineComment = false;
+ lineOpensWithComment = false;
+ lineStartsInComment = isInComment;
+ previousLineProbationTab = false;
+ lineOpeningBlocksNum = 0;
+ lineClosingBlocksNum = 0;
+ if (isImmediatelyPostObjCMethodDefinition)
+ clearObjCMethodDefinitionAlignment();
+ if (isImmediatelyPostObjCMethodCall)
+ {
+ isImmediatelyPostObjCMethodCall = false;
+ isInObjCMethodCall = false;
+ objCColonAlignSubsequent = 0;
+ }
+
+ // 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 brace open the line
+ size_t firstChar = line.find_first_not_of(" \t");
+ if (firstChar != string::npos)
+ {
+ if (line[firstChar] == '{')
+ lineBeginsWithOpenBrace = true;
+ else if (line[firstChar] == '}')
+ lineBeginsWithCloseBrace = true;
+ else if (line[firstChar] == ',')
+ lineBeginsWithComma = true;
+ }
+ }
+ else
+ {
+ line = trim(originalLine);
+ if (line.length() > 0)
+ {
+ if (line[0] == '{')
+ lineBeginsWithOpenBrace = true;
+ else if (line[0] == '}')
+ lineBeginsWithCloseBrace = true;
+ else if (line[0] == ',')
+ lineBeginsWithComma = true;
+ else if (line.compare(0, 2, "//") == 0)
+ lineIsLineCommentOnly = true;
+ else if (line.compare(0, 2, "/*") == 0)
+ {
+ if (line.find("*/", 2) != string::npos)
+ lineIsCommentOnly = true;
+ }
+ }
+
+ isInRunInComment = 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)
+ isInRunInComment = true;
+ }
+ }
+
+ // When indent is OFF the lines must still be processed by ASBeautifier.
+ // Otherwise the lines immediately following may not be indented correctly.
+ if ((lineIsLineCommentOnly || lineIsCommentOnly)
+ && line.find("*INDENT-OFF*", 0) != string::npos)
+ isIndentModeOff = true;
+
+ if (line.length() == 0)
+ {
+ if (backslashEndsPrevLine)
+ {
+ backslashEndsPrevLine = false;
+ // check if this line ends a multi-line #define
+ // if so, remove the #define's cloned beautifier from the active
+ // beautifier stack and delete it.
+ if (isInDefineDefinition && !isInDefine)
+ {
+ isInDefineDefinition = false;
+ ASBeautifier* defineBeautifier = activeBeautifierStack->back();
+ activeBeautifierStack->pop_back();
+ delete defineBeautifier;
+ }
+ }
+ if (emptyLineFill && !isInQuoteContinuation)
+ {
+ if (isInIndentablePreprocBlock)
+ return preLineWS(preprocBlockIndent, 0);
+ if (!headerStack->empty() || isInEnum)
+ return preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount);
+ // must fall thru here
+ }
+ else
+ return line;
+ }
+
+ // handle preprocessor commands
+ if (isInIndentablePreprocBlock
+ && line.length() > 0
+ && line[0] != '#')
+ {
+ string indentedLine;
+ if (isInClassHeaderTab || isInClassInitializer)
+ {
+ // parsing is turned off in ASFormatter by indent-off
+ // the originalLine will probably never be returned here
+ indentedLine = preLineWS(prevFinalLineIndentCount, prevFinalLineSpaceIndentCount) + line;
+ return getIndentedLineReturn(indentedLine, originalLine);
+ }
+ indentedLine = preLineWS(preprocBlockIndent, 0) + line;
+ return getIndentedLineReturn(indentedLine, originalLine);
+ }
+
+ if (!isInComment
+ && !isInQuoteContinuation
+ && line.length() > 0
+ && ((line[0] == '#' && !isIndentedPreprocessor(line, 0))
+ || backslashEndsPrevLine))
+ {
+ if (line[0] == '#' && !isInDefine)
+ {
+ string preproc = extractPreprocessorStatement(line);
+ processPreprocessor(preproc, line);
+ if (isInIndentablePreprocBlock || isInIndentablePreproc)
+ {
+ string indentedLine;
+ if ((preproc.length() >= 2 && preproc.substr(0, 2) == "if")) // #if, #ifdef, #ifndef
+ {
+ indentedLine = preLineWS(preprocBlockIndent, 0) + line;
+ preprocBlockIndent += 1;
+ isInIndentablePreprocBlock = true;
+ }
+ else if (preproc == "else" || preproc == "elif")
+ {
+ indentedLine = preLineWS(preprocBlockIndent - 1, 0) + line;
+ }
+ else if (preproc == "endif")
+ {
+ preprocBlockIndent -= 1;
+ indentedLine = preLineWS(preprocBlockIndent, 0) + line;
+ if (preprocBlockIndent == 0)
+ isInIndentablePreprocBlock = false;
+ }
+ else
+ indentedLine = preLineWS(preprocBlockIndent, 0) + line;
+ return getIndentedLineReturn(indentedLine, originalLine);
+ }
+ if (shouldIndentPreprocConditional && preproc.length() > 0)
+ {
+ string indentedLine;
+ if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
+ {
+ pair<int, int> entry; // indentCount, spaceIndentCount
+ if (!isInDefine && activeBeautifierStack != nullptr && !activeBeautifierStack->empty())
+ entry = activeBeautifierStack->back()->computePreprocessorIndent();
+ else
+ entry = computePreprocessorIndent();
+ preprocIndentStack->emplace_back(entry);
+ indentedLine = preLineWS(preprocIndentStack->back().first,
+ preprocIndentStack->back().second) + line;
+ return getIndentedLineReturn(indentedLine, originalLine);
+ }
+ if (preproc == "else" || preproc == "elif")
+ {
+ if (!preprocIndentStack->empty()) // if no entry don't indent
+ {
+ indentedLine = preLineWS(preprocIndentStack->back().first,
+ preprocIndentStack->back().second) + line;
+ return getIndentedLineReturn(indentedLine, originalLine);
+ }
+ }
+ else if (preproc == "endif")
+ {
+ if (!preprocIndentStack->empty()) // if no entry don't indent
+ {
+ indentedLine = preLineWS(preprocIndentStack->back().first,
+ preprocIndentStack->back().second) + line;
+ preprocIndentStack->pop_back();
+ return getIndentedLineReturn(indentedLine, originalLine);
+ }
+ }
+ }
+ }
+
+ // 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)
+ {
+ isInDefineDefinition = false;
+ ASBeautifier* defineBeautifier = activeBeautifierStack->back();
+ activeBeautifierStack->pop_back();
+
+ string indentedLine = defineBeautifier->beautify(line);
+ delete defineBeautifier;
+ return getIndentedLineReturn(indentedLine, originalLine);
+ }
+
+ // 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 != nullptr && !activeBeautifierStack->empty())
+ {
+ activeBeautifierStack->back()->inLineNumber = inLineNumber;
+ activeBeautifierStack->back()->runInIndentContinuation = runInIndentContinuation;
+ activeBeautifierStack->back()->nonInStatementBrace = nonInStatementBrace;
+ activeBeautifierStack->back()->objCColonAlignSubsequent = objCColonAlignSubsequent;
+ 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;
+ activeBeautifierStack->back()->isInIndentablePreproc = isInIndentablePreproc;
+ // 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()
+ && lineBeginsWithOpenBrace
+ && (headerStack->back() != &AS_OPEN_BRACE
+ || probationHeader != nullptr))
+ 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);
+
+ if (isInObjCMethodDefinition)
+ adjustObjCMethodDefinitionIndentation(line);
+
+ if (isInObjCMethodCall)
+ adjustObjCMethodCallIndentation(line);
+
+ 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 (!continuationIndentStack->empty()
+ && continuationIndentStack->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 beginning of line
+
+ string indentedLine = preLineWS(indentCount, spaceIndentCount) + line;
+ indentedLine = getIndentedLineReturn(indentedLine, originalLine);
+
+ prevFinalLineSpaceIndentCount = spaceIndentCount;
+ prevFinalLineIndentCount = indentCount;
+
+ if (lastLineHeader != nullptr)
+ previousLastLineHeader = lastLineHeader;
+
+ if ((lineIsLineCommentOnly || lineIsCommentOnly)
+ && line.find("*INDENT-ON*", 0) != string::npos)
+ isIndentModeOff = false;
+
+ return indentedLine;
+}
+
+const string& ASBeautifier::getIndentedLineReturn(const string& newLine, const string& originalLine) const
+{
+ if (isIndentModeOff)
+ return originalLine;
+ return newLine;
+}
+
+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 a continuation indent.
+ */
+void ASBeautifier::registerContinuationIndent(const string& line, int i, int spaceIndentCount_,
+ int tabIncrementIn, int minIndent, bool updateParenStack)
+{
+ int remainingCharNum = line.length() - i;
+ int nextNonWSChar = getNextProgramCharDistance(line, i);
+
+ // if indent is around the last char in the line OR indent-after-paren is requested,
+ // indent with the continuation indent
+ if (nextNonWSChar == remainingCharNum || shouldIndentAfterParen)
+ {
+ int previousIndent = spaceIndentCount_;
+ if (!continuationIndentStack->empty())
+ previousIndent = continuationIndentStack->back();
+ int currIndent = continuationIndent * indentLength + previousIndent;
+ if (currIndent > maxContinuationIndent && line[i] != '{')
+ currIndent = indentLength * 2 + spaceIndentCount_;
+ continuationIndentStack->emplace_back(currIndent);
+ if (updateParenStack)
+ parenIndentStack->emplace_back(previousIndent);
+ return;
+ }
+
+ if (updateParenStack)
+ parenIndentStack->emplace_back(i + spaceIndentCount_ - runInIndentContinuation);
+
+ int tabIncrement = tabIncrementIn;
+
+ // check for following tabs
+ for (int j = i + 1; j < (i + nextNonWSChar); j++)
+ {
+ if (line[j] == '\t')
+ tabIncrement += convertTabToSpaces(j, tabIncrement);
+ }
+
+ int continuationIndentCount = i + nextNonWSChar + spaceIndentCount_ + tabIncrement;
+
+ // check for run-in statement
+ if (i > 0 && line[0] == '{')
+ continuationIndentCount -= indentLength;
+
+ if (continuationIndentCount < minIndent)
+ continuationIndentCount = minIndent + spaceIndentCount_;
+
+ // this is not done for an in-statement array
+ if (continuationIndentCount > maxContinuationIndent
+ && !(prevNonLegalCh == '=' && currentNonLegalCh == '{'))
+ continuationIndentCount = indentLength * 2 + spaceIndentCount_;
+
+ if (!continuationIndentStack->empty()
+ && continuationIndentCount < continuationIndentStack->back())
+ continuationIndentCount = continuationIndentStack->back();
+
+ // the block opener is not indented for a NonInStatementArray
+ if ((isNonInStatementArray && line[i] == '{')
+ && !isInEnum && !braceBlockStateStack->empty() && braceBlockStateStack->back())
+ continuationIndentCount = 0;
+
+ continuationIndentStack->emplace_back(continuationIndentCount);
+}
+
+/**
+* Register a continuation indent for a class header or a class initializer colon.
+*/
+void ASBeautifier::registerContinuationIndentColon(const string& line, int i, int tabIncrementIn)
+{
+ assert(line[i] == ':');
+ assert(isInClassInitializer || isInClassHeaderTab);
+
+ // register indent at first word after the colon
+ size_t firstChar = line.find_first_not_of(" \t");
+ if (firstChar == (size_t) i) // firstChar is ':'
+ {
+ size_t firstWord = line.find_first_not_of(" \t", firstChar + 1);
+ if (firstChar != string::npos)
+ {
+ int continuationIndentCount = firstWord + spaceIndentCount + tabIncrementIn;
+ continuationIndentStack->emplace_back(continuationIndentCount);
+ isContinuation = true;
+ }
+ }
+}
+
+/**
+ * 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;
+ if (line.compare(i + charDistance, 2, "/*") == 0)
+ {
+ charDistance++;
+ inComment = true;
+ }
+ }
+ else
+ return charDistance;
+ }
+
+ return charDistance;
+}
+
+/**
+ * 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(const 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;
+ 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->emplace_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 != nullptr)
+ {
+ container->clear();
+ delete (container);
+ container = nullptr;
+ }
+}
+
+/**
+ * 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 != nullptr)
+ {
+ vector<ASBeautifier*>::iterator iter = container->begin();
+ while (iter < container->end())
+ {
+ delete *iter;
+ ++iter;
+ }
+ container->clear();
+ delete (container);
+ container = nullptr;
+ }
+}
+
+/**
+ * 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 != nullptr)
+ {
+ vector<vector<const string*>*>::iterator iter = container->begin();
+ while (iter < container->end())
+ {
+ delete *iter;
+ ++iter;
+ }
+ container->clear();
+ delete (container);
+ container = nullptr;
+ }
+}
+
+/**
+ * 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 != nullptr)
+ deleteContainer(container);
+ container = value;
+}
+
+/**
+ * Initialize the tempStacks vector object.
+ * The tempStacks is a vector of pointers to strings allocated with the 'new' operator.
+ * Any residual entries are deleted before the vector is initialized.
+ */
+void ASBeautifier::initTempStacksContainer(vector<vector<const string*>*>*& container,
+ vector<vector<const string*>*>* value)
+{
+ if (container != nullptr)
+ deleteTempStacksContainer(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 == '\'' && !isDigitSeparator(line, i)))
+ {
+ 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::getContinuationIndentAssign(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::getContinuationIndentComma(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" and "endregion" are always indented.
+ * C/C++ "pragma omp" is always indented.
+ *
+ * @return is true or false.
+ */
+bool ASBeautifier::isIndentedPreprocessor(const string& line, size_t currPos) const
+{
+ assert(line[0] == '#');
+ string nextWord = getNextWord(line, currPos);
+ if (nextWord == "region" || nextWord == "endregion")
+ return true;
+ // is it #pragma omp
+ if (nextWord == "pragma")
+ {
+ // find pragma
+ size_t start = line.find("pragma");
+ if (start == string::npos || !isLegalNameChar(line[start]))
+ return false;
+ // bypass pragma
+ for (; start < line.length(); start++)
+ {
+ if (!isLegalNameChar(line[start]))
+ break;
+ }
+ start++;
+ if (start >= line.length())
+ return false;
+ // point to start of second word
+ start = line.find_first_not_of(" \t", start);
+ if (start == string::npos)
+ return false;
+ // point to end of second word
+ size_t end;
+ for (end = start; end < line.length(); end++)
+ {
+ if (!isLegalNameChar(line[end]))
+ break;
+ }
+ // check for "pragma omp"
+ string word = line.substr(start, end - start);
+ if (word == "omp" || word == "region" || word == "endregion")
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Check if a preprocessor directive is checking for __cplusplus defined.
+ *
+ * @return is true or false.
+ */
+bool ASBeautifier::isPreprocessorConditionalCplusplus(const string& line) const
+{
+ string preproc = trim(line.substr(1));
+ if (preproc.compare(0, 5, "ifdef") == 0 && getNextWord(preproc, 4) == "__cplusplus")
+ return true;
+ if (preproc.compare(0, 2, "if") == 0)
+ {
+ // check for " #if defined(__cplusplus)"
+ size_t charNum = 2;
+ charNum = preproc.find_first_not_of(" \t", charNum);
+ if (charNum != string::npos && preproc.compare(charNum, 7, "defined") == 0)
+ {
+ charNum += 7;
+ charNum = preproc.find_first_not_of(" \t", charNum);
+ if (preproc.compare(charNum, 1, "(") == 0)
+ {
+ ++charNum;
+ charNum = preproc.find_first_not_of(" \t", charNum);
+ if (preproc.compare(charNum, 11, "__cplusplus") == 0)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Check if a preprocessor definition contains an unterminated comment.
+ * Comments within a preprocessor definition can be continued without the backslash.
+ *
+ * @return is true or false.
+ */
+bool ASBeautifier::isInPreprocessorUnterminatedComment(const string& line)
+{
+ if (!isInPreprocessorComment)
+ {
+ size_t startPos = line.find("/*");
+ if (startPos == string::npos)
+ return false;
+ }
+ size_t endNum = line.find("*/");
+ if (endNum != string::npos)
+ {
+ isInPreprocessorComment = false;
+ return false;
+ }
+ isInPreprocessorComment = true;
+ return true;
+}
+
+void ASBeautifier::popLastContinuationIndent()
+{
+ assert(!continuationIndentStackSizeStack->empty());
+ int previousIndentStackSize = continuationIndentStackSizeStack->back();
+ if (continuationIndentStackSizeStack->size() > 1)
+ continuationIndentStackSizeStack->pop_back();
+ while (previousIndentStackSize < (int) continuationIndentStack->size())
+ continuationIndentStack->pop_back();
+}
+
+// for unit testing
+int ASBeautifier::getBeautifierFileType() const
+{ return beautifierFileType; }
+
+/**
+ * Process preprocessor statements and update the beautifier stacks.
+ */
+void ASBeautifier::processPreprocessor(const string& preproc, const string& line)
+{
+ // When finding a multi-lined #define statement, the original beautifier
+ // 1. sets its isInDefineDefinition flag
+ // 2. clones a new beautifier that will be used for the actual indentation
+ // of the #define. This clone is put into the activeBeautifierStack in order
+ // to be called for the actual indentation.
+ // The original beautifier will have isInDefineDefinition = true, isInDefine = false
+ // The cloned beautifier will have isInDefineDefinition = true, isInDefine = true
+ if (shouldIndentPreprocDefine && preproc == "define" && line[line.length() - 1] == '\\')
+ {
+ if (!isInDefineDefinition)
+ {
+ // this is the original beautifier
+ isInDefineDefinition = true;
+
+ // push a new beautifier into the active stack
+ // this beautifier will be used for the indentation of this define
+ ASBeautifier* defineBeautifier = new ASBeautifier(*this);
+ activeBeautifierStack->emplace_back(defineBeautifier);
+ }
+ else
+ {
+ // the is the cloned beautifier that is in charge of indenting the #define.
+ isInDefine = true;
+ }
+ }
+ else if (preproc.length() >= 2 && preproc.substr(0, 2) == "if")
+ {
+ if (isPreprocessorConditionalCplusplus(line) && !g_preprocessorCppExternCBrace)
+ g_preprocessorCppExternCBrace = 1;
+ // push a new beautifier into the stack
+ waitingBeautifierStackLengthStack->push_back(waitingBeautifierStack->size());
+ activeBeautifierStackLengthStack->push_back(activeBeautifierStack->size());
+ if (activeBeautifierStackLengthStack->back() == 0)
+ waitingBeautifierStack->emplace_back(new ASBeautifier(*this));
+ else
+ waitingBeautifierStack->emplace_back(new ASBeautifier(*activeBeautifierStack->back()));
+ }
+ else if (preproc == "else")
+ {
+ if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
+ {
+ // MOVE current waiting beautifier to active stack.
+ activeBeautifierStack->emplace_back(waitingBeautifierStack->back());
+ waitingBeautifierStack->pop_back();
+ }
+ }
+ else if (preproc == "elif")
+ {
+ if ((waitingBeautifierStack != nullptr) && !waitingBeautifierStack->empty())
+ {
+ // append a COPY current waiting beautifier to active stack, WITHOUT deleting the original.
+ activeBeautifierStack->emplace_back(new ASBeautifier(*(waitingBeautifierStack->back())));
+ }
+ }
+ else if (preproc == "endif")
+ {
+ int stackLength = 0;
+ ASBeautifier* beautifier = nullptr;
+
+ if (waitingBeautifierStackLengthStack != nullptr && !waitingBeautifierStackLengthStack->empty())
+ {
+ stackLength = waitingBeautifierStackLengthStack->back();
+ waitingBeautifierStackLengthStack->pop_back();
+ while ((int) waitingBeautifierStack->size() > stackLength)
+ {
+ beautifier = waitingBeautifierStack->back();
+ waitingBeautifierStack->pop_back();
+ delete beautifier;
+ }
+ }
+
+ if (!activeBeautifierStackLengthStack->empty())
+ {
+ stackLength = activeBeautifierStackLengthStack->back();
+ activeBeautifierStackLengthStack->pop_back();
+ while ((int) activeBeautifierStack->size() > stackLength)
+ {
+ beautifier = activeBeautifierStack->back();
+ activeBeautifierStack->pop_back();
+ delete beautifier;
+ }
+ }
+ }
+}
+
+// Compute the preliminary indentation based on data in the headerStack
+// and data from previous lines.
+// Update the class variable indentCount.
+void ASBeautifier::computePreliminaryIndentation()
+{
+ indentCount = 0;
+ spaceIndentCount = 0;
+ isInClassHeaderTab = false;
+
+ if (isInObjCMethodDefinition && !continuationIndentStack->empty())
+ spaceIndentObjCMethodAlignment = continuationIndentStack->back();
+
+ if (!continuationIndentStack->empty())
+ spaceIndentCount = continuationIndentStack->back();
+
+ for (size_t i = 0; i < headerStack->size(); i++)
+ {
+ isInClass = false;
+
+ if (blockIndent)
+ {
+ // do NOT indent opening block for these headers
+ if (!((*headerStack)[i] == &AS_NAMESPACE
+ || (*headerStack)[i] == &AS_MODULE
+ || (*headerStack)[i] == &AS_CLASS
+ || (*headerStack)[i] == &AS_STRUCT
+ || (*headerStack)[i] == &AS_UNION
+ || (*headerStack)[i] == &AS_INTERFACE
+ || (*headerStack)[i] == &AS_THROWS
+ || (*headerStack)[i] == &AS_STATIC))
+ ++indentCount;
+ }
+ else if (!(i > 0 && (*headerStack)[i - 1] != &AS_OPEN_BRACE
+ && (*headerStack)[i] == &AS_OPEN_BRACE))
+ ++indentCount;
+
+ if (!isJavaStyle() && !namespaceIndent && i > 0
+ && ((*headerStack)[i - 1] == &AS_NAMESPACE
+ || (*headerStack)[i - 1] == &AS_MODULE)
+ && (*headerStack)[i] == &AS_OPEN_BRACE)
+ --indentCount;
+
+ if (isCStyle() && i >= 1
+ && (*headerStack)[i - 1] == &AS_CLASS
+ && (*headerStack)[i] == &AS_OPEN_BRACE)
+ {
+ if (classIndent)
+ ++indentCount;
+ isInClass = true;
+ }
+
+ // is the switchIndent option is on, indent switch statements an additional indent.
+ else if (switchIndent && i > 1
+ && (*headerStack)[i - 1] == &AS_SWITCH
+ && (*headerStack)[i] == &AS_OPEN_BRACE)
+ {
+ ++indentCount;
+ isInSwitch = true;
+ }
+
+ } // end of for loop
+
+ if (isInClassHeader)
+ {
+ if (!isJavaStyle())
+ isInClassHeaderTab = true;
+ if (lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment)
+ {
+ if (!lineBeginsWithOpenBrace)
+ --indentCount;
+ if (!continuationIndentStack->empty())
+ spaceIndentCount -= continuationIndentStack->back();
+ }
+ else if (blockIndent)
+ {
+ if (!lineBeginsWithOpenBrace)
+ ++indentCount;
+ }
+ }
+
+ if (isInClassInitializer || isInEnumTypeID)
+ {
+ indentCount += classInitializerIndents;
+ }
+
+ if (isInEnum && lineBeginsWithComma && !continuationIndentStack->empty())
+ {
+ // unregister '=' indent from the previous line
+ continuationIndentStack->pop_back();
+ isContinuation = false;
+ spaceIndentCount = 0;
+ }
+
+ // Objective-C interface continuation line
+ if (isInObjCInterface)
+ ++indentCount;
+
+ // unindent a class closing brace...
+ if (!lineStartsInComment
+ && isCStyle()
+ && isInClass
+ && classIndent
+ && headerStack->size() >= 2
+ && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
+ && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
+ && lineBeginsWithCloseBrace
+ && braceBlockStateStack->back())
+ --indentCount;
+
+ // unindent an indented switch closing brace...
+ else if (!lineStartsInComment
+ && isInSwitch
+ && switchIndent
+ && headerStack->size() >= 2
+ && (*headerStack)[headerStack->size() - 2] == &AS_SWITCH
+ && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE
+ && lineBeginsWithCloseBrace)
+ --indentCount;
+
+ // handle special case of run-in comment in an indented class statement
+ if (isInClass
+ && classIndent
+ && isInRunInComment
+ && !lineOpensWithComment
+ && headerStack->size() > 1
+ && (*headerStack)[headerStack->size() - 2] == &AS_CLASS)
+ --indentCount;
+
+ if (isInConditional)
+ --indentCount;
+ if (g_preprocessorCppExternCBrace >= 4)
+ --indentCount;
+}
+
+void ASBeautifier::adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHeaderIndent)
+{
+ if (lineStartsInComment)
+ return;
+
+ // unindent a one-line statement in a header indent
+ if (!blockIndent
+ && lineBeginsWithOpenBrace
+ && headerStack->size() < iPrelim
+ && isInExtraHeaderIndent
+ && (lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
+ && shouldIndentBracedLine)
+ --indentCount;
+
+ /*
+ * if '{' doesn't follow an immediately previous '{' in the headerStack
+ * (but rather another header such as "for" or "if", then unindent it
+ * by one indentation relative to its block.
+ */
+ else if (!blockIndent
+ && lineBeginsWithOpenBrace
+ && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
+ && (headerStack->size() > 1 && (*headerStack)[headerStack->size() - 2] != &AS_OPEN_BRACE)
+ && shouldIndentBracedLine)
+ --indentCount;
+
+ // must check one less in headerStack if more than one header on a line (allow-addins)...
+ else if (headerStack->size() > iPrelim + 1
+ && !blockIndent
+ && lineBeginsWithOpenBrace
+ && !(lineOpeningBlocksNum > 0 && lineOpeningBlocksNum <= lineClosingBlocksNum)
+ && (headerStack->size() > 2 && (*headerStack)[headerStack->size() - 3] != &AS_OPEN_BRACE)
+ && shouldIndentBracedLine)
+ --indentCount;
+
+ // unindent a closing brace...
+ else if (lineBeginsWithCloseBrace
+ && shouldIndentBracedLine)
+ --indentCount;
+
+ // correctly indent one-line-blocks...
+ else if (lineOpeningBlocksNum > 0
+ && lineOpeningBlocksNum == lineClosingBlocksNum
+ && previousLineProbationTab)
+ --indentCount;
+
+ if (indentCount < 0)
+ indentCount = 0;
+
+ // take care of extra brace indentation option...
+ if (!lineStartsInComment
+ && braceIndent
+ && shouldIndentBracedLine
+ && (lineBeginsWithOpenBrace || lineBeginsWithCloseBrace))
+ {
+ if (!braceIndentVtk)
+ ++indentCount;
+ else
+ {
+ // determine if a style VTK brace is indented
+ bool haveUnindentedBrace = false;
+ for (size_t i = 0; i < headerStack->size(); i++)
+ {
+ if (((*headerStack)[i] == &AS_NAMESPACE
+ || (*headerStack)[i] == &AS_MODULE
+ || (*headerStack)[i] == &AS_CLASS
+ || (*headerStack)[i] == &AS_STRUCT)
+ && i + 1 < headerStack->size()
+ && (*headerStack)[i + 1] == &AS_OPEN_BRACE)
+ i++;
+ else if (lineBeginsWithOpenBrace)
+ {
+ // don't double count the current brace
+ if (i + 1 < headerStack->size()
+ && (*headerStack)[i] == &AS_OPEN_BRACE)
+ haveUnindentedBrace = true;
+ }
+ else if ((*headerStack)[i] == &AS_OPEN_BRACE)
+ haveUnindentedBrace = true;
+ } // end of for loop
+ if (haveUnindentedBrace)
+ ++indentCount;
+ }
+ }
+}
+
+/**
+ * Compute indentCount adjustment when in a series of else-if statements
+ * and shouldBreakElseIfs is requested.
+ * It increments by one for each 'else' in the tempStack.
+ */
+int ASBeautifier::adjustIndentCountForBreakElseIfComments() const
+{
+ assert(isElseHeaderIndent && !tempStacks->empty());
+ int indentCountIncrement = 0;
+ vector<const string*>* lastTempStack = tempStacks->back();
+ if (lastTempStack != nullptr)
+ {
+ for (size_t i = 0; i < lastTempStack->size(); i++)
+ {
+ if (*lastTempStack->at(i) == AS_ELSE)
+ indentCountIncrement++;
+ }
+ }
+ return indentCountIncrement;
+}
+
+/**
+ * Extract a preprocessor statement without the #.
+ * If a error occurs an empty string is returned.
+ */
+string ASBeautifier::extractPreprocessorStatement(const string& line) const
+{
+ string preproc;
+ size_t start = line.find_first_not_of("#/ \t");
+ if (start == string::npos)
+ return preproc;
+ size_t end = line.find_first_of("/ \t", start);
+ if (end == string::npos)
+ end = line.length();
+ preproc = line.substr(start, end - start);
+ return preproc;
+}
+
+void ASBeautifier::adjustObjCMethodDefinitionIndentation(const string& line_)
+{
+ // register indent for Objective-C continuation line
+ if (line_.length() > 0
+ && (line_[0] == '-' || line_[0] == '+'))
+ {
+ if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
+ {
+ string convertedLine = getIndentedSpaceEquivalent(line_);
+ colonIndentObjCMethodAlignment = convertedLine.find(':');
+ int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
+ if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
+ colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
+ }
+ else if (continuationIndentStack->empty()
+ || continuationIndentStack->back() == 0)
+ {
+ continuationIndentStack->emplace_back(indentLength);
+ isContinuation = true;
+ }
+ }
+ // set indent for last definition line
+ else if (!lineBeginsWithOpenBrace)
+ {
+ if (shouldAlignMethodColon)
+ spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
+ else if (continuationIndentStack->empty())
+ spaceIndentCount = spaceIndentObjCMethodAlignment;
+ }
+}
+
+void ASBeautifier::adjustObjCMethodCallIndentation(const string& line_)
+{
+ static int keywordIndentObjCMethodAlignment = 0;
+ if (shouldAlignMethodColon && objCColonAlignSubsequent != -1)
+ {
+ if (isInObjCMethodCallFirst)
+ {
+ isInObjCMethodCallFirst = false;
+ string convertedLine = getIndentedSpaceEquivalent(line_);
+ bracePosObjCMethodAlignment = convertedLine.find('[');
+ keywordIndentObjCMethodAlignment =
+ getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
+ colonIndentObjCMethodAlignment = convertedLine.find(':');
+ if (colonIndentObjCMethodAlignment >= 0)
+ {
+ int objCColonAlignSubsequentIndent = objCColonAlignSubsequent + indentLength;
+ if (objCColonAlignSubsequentIndent > colonIndentObjCMethodAlignment)
+ colonIndentObjCMethodAlignment = objCColonAlignSubsequentIndent;
+ if (lineBeginsWithOpenBrace)
+ colonIndentObjCMethodAlignment -= indentLength;
+ }
+ }
+ else
+ {
+ if (line_.find(':') != string::npos)
+ {
+ if (colonIndentObjCMethodAlignment < 0)
+ spaceIndentCount += computeObjCColonAlignment(line_, objCColonAlignSubsequent);
+ else if (objCColonAlignSubsequent > colonIndentObjCMethodAlignment)
+ spaceIndentCount = computeObjCColonAlignment(line_, objCColonAlignSubsequent);
+ else
+ spaceIndentCount = computeObjCColonAlignment(line_, colonIndentObjCMethodAlignment);
+ }
+ else
+ {
+ if (spaceIndentCount < colonIndentObjCMethodAlignment)
+ spaceIndentCount += keywordIndentObjCMethodAlignment;
+ }
+ }
+ }
+ else // align keywords instead of colons
+ {
+ if (isInObjCMethodCallFirst)
+ {
+ isInObjCMethodCallFirst = false;
+ string convertedLine = getIndentedSpaceEquivalent(line_);
+ bracePosObjCMethodAlignment = convertedLine.find('[');
+ keywordIndentObjCMethodAlignment =
+ getObjCFollowingKeyword(convertedLine, bracePosObjCMethodAlignment);
+ }
+ else
+ {
+ if (spaceIndentCount < keywordIndentObjCMethodAlignment + bracePosObjCMethodAlignment)
+ spaceIndentCount += keywordIndentObjCMethodAlignment;
+ }
+ }
+}
+
+/**
+ * Clear the variables used to align the Objective-C method definitions.
+ */
+void ASBeautifier::clearObjCMethodDefinitionAlignment()
+{
+ assert(isImmediatelyPostObjCMethodDefinition);
+ spaceIndentCount = 0;
+ spaceIndentObjCMethodAlignment = 0;
+ colonIndentObjCMethodAlignment = 0;
+ isInObjCMethodDefinition = false;
+ isImmediatelyPostObjCMethodDefinition = false;
+ if (!continuationIndentStack->empty())
+ continuationIndentStack->pop_back();
+}
+
+/**
+ * Compute the spaceIndentCount necessary to align the current line colon
+ * with the colon position in the argument.
+ * If it cannot be aligned indentLength is returned and a new colon
+ * position is calculated.
+ */
+int ASBeautifier::computeObjCColonAlignment(const string& line, int colonAlignPosition) const
+{
+ int colonPosition = line.find(':');
+ if (colonPosition < 0 || colonPosition > colonAlignPosition)
+ return indentLength;
+ return (colonAlignPosition - colonPosition);
+}
+
+/*
+ * Compute postition of the keyword following the method call object.
+ */
+int ASBeautifier::getObjCFollowingKeyword(const string& line, int bracePos) const
+{
+ assert(line[bracePos] == '[');
+ size_t firstText = line.find_first_not_of(" \t", bracePos + 1);
+ if (firstText == string::npos)
+ return -(indentCount * indentLength - 1);
+ size_t searchBeg = firstText;
+ size_t objectEnd = 0; // end of object text
+ if (line[searchBeg] == '[')
+ {
+ objectEnd = line.find(']', searchBeg + 1);
+ if (objectEnd == string::npos)
+ return 0;
+ }
+ else
+ {
+ if (line[searchBeg] == '(')
+ {
+ searchBeg = line.find(')', searchBeg + 1);
+ if (searchBeg == string::npos)
+ return 0;
+ }
+ // bypass the object name
+ objectEnd = line.find_first_of(" \t", searchBeg + 1);
+ if (objectEnd == string::npos)
+ return 0;
+ --objectEnd;
+ }
+ size_t keyPos = line.find_first_not_of(" \t", objectEnd + 1);
+ if (keyPos == string::npos)
+ return 0;
+ return keyPos - firstText;
+}
+
+/**
+ * Get a line using the current space indent with all tabs replaced by spaces.
+ * The indentCount is NOT included
+ * Needed to compute an accurate alignment.
+ */
+string ASBeautifier::getIndentedSpaceEquivalent(const string& line_) const
+{
+ string spaceIndent;
+ spaceIndent.append(spaceIndentCount, ' ');
+ string convertedLine = spaceIndent + line_;
+ for (size_t i = spaceIndent.length(); i < convertedLine.length(); i++)
+ {
+ if (convertedLine[i] == '\t')
+ {
+ size_t numSpaces = indentLength - (i % indentLength);
+ convertedLine.replace(i, 1, numSpaces, ' ');
+ i += indentLength - 1;
+ }
+ }
+ return convertedLine;
+}
+
+/**
+ * Parse the current line to update indentCount and spaceIndentCount.
+ */
+void ASBeautifier::parseCurrentLine(const string& line)
+{
+ bool isInLineComment = false;
+ bool isInOperator = false;
+ bool isSpecialChar = false;
+ bool haveCaseIndent = false;
+ bool haveAssignmentThisLine = false;
+ bool closingBraceReached = false;
+ bool previousLineProbation = (probationHeader != nullptr);
+ char ch = ' ';
+ int tabIncrementIn = 0;
+ if (isInQuote
+ && !haveLineContinuationChar
+ && !isInVerbatimQuote
+ && !isInAsm)
+ isInQuote = false; // missing closing quote
+ haveLineContinuationChar = false;
+
+ for (size_t i = 0; i < line.length(); i++)
+ {
+ ch = line[i];
+
+ if (isInBeautifySQL)
+ continue;
+
+ // handle special characters (i.e. backslash+character such as \n, \t, ...)
+ if (isInQuote && !isInVerbatimQuote)
+ {
+ if (isSpecialChar)
+ {
+ isSpecialChar = false;
+ continue;
+ }
+ if (line.compare(i, 2, "\\\\") == 0)
+ {
+ i++;
+ continue;
+ }
+ if (ch == '\\')
+ {
+ if (peekNextChar(line, i) == ' ') // is this '\' at end of line
+ haveLineContinuationChar = true;
+ else
+ isSpecialChar = true;
+ continue;
+ }
+ }
+ else if (isInDefine && ch == '\\')
+ continue;
+
+ // bypass whitespace here
+ if (isWhiteSpace(ch))
+ {
+ if (ch == '\t')
+ tabIncrementIn += convertTabToSpaces(i, tabIncrementIn);
+ continue;
+ }
+
+ // handle quotes (such as 'x' and "Hello Dolly")
+ if (!(isInComment || isInLineComment)
+ && (ch == '"'
+ || (ch == '\'' && !isDigitSeparator(line, i))))
+ {
+ if (!isInQuote)
+ {
+ quoteChar = ch;
+ isInQuote = true;
+ char prevCh = i > 0 ? line[i - 1] : ' ';
+ if (isCStyle() && prevCh == 'R')
+ {
+ int parenPos = line.find('(', i);
+ if (parenPos != -1)
+ {
+ isInVerbatimQuote = true;
+ verbatimDelimiter = line.substr(i + 1, parenPos - i - 1);
+ }
+ }
+ else if (isSharpStyle() && prevCh == '@')
+ isInVerbatimQuote = true;
+ // check for "C" following "extern"
+ else if (g_preprocessorCppExternCBrace == 2 && line.compare(i, 3, "\"C\"") == 0)
+ ++g_preprocessorCppExternCBrace;
+ }
+ else if (isInVerbatimQuote && ch == '"')
+ {
+ if (isCStyle())
+ {
+ string delim = ')' + verbatimDelimiter;
+ int delimStart = i - delim.length();
+ if (delimStart > 0 && line.substr(delimStart, delim.length()) == delim)
+ {
+ isInQuote = false;
+ isInVerbatimQuote = false;
+ }
+ }
+ else if (isSharpStyle())
+ {
+ if (line.compare(i, 2, "\"\"") == 0)
+ i++;
+ else
+ {
+ isInQuote = false;
+ isInVerbatimQuote = false;
+ continue;
+ }
+ }
+ }
+ else if (quoteChar == ch)
+ {
+ isInQuote = false;
+ isContinuation = true;
+ continue;
+ }
+ }
+ if (isInQuote)
+ continue;
+
+ // handle comments
+
+ if (!(isInComment || isInLineComment) && line.compare(i, 2, "//") == 0)
+ {
+ // if there is a 'case' statement after these comments unindent by 1
+ if (isCaseHeaderCommentIndent)
+ --indentCount;
+ // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
+ // if there is an 'else' after these comments a tempStacks indent is required
+ if (isElseHeaderIndent && lineOpensWithLineComment && !tempStacks->empty())
+ indentCount += adjustIndentCountForBreakElseIfComments();
+ isInLineComment = true;
+ i++;
+ continue;
+ }
+ else if (!(isInComment || isInLineComment) && line.compare(i, 2, "/*") == 0)
+ {
+ // if there is a 'case' statement after these comments unindent by 1
+ if (isCaseHeaderCommentIndent && lineOpensWithComment)
+ --indentCount;
+ // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
+ // if there is an 'else' after these comments a tempStacks indent is required
+ if (isElseHeaderIndent && lineOpensWithComment && !tempStacks->empty())
+ indentCount += adjustIndentCountForBreakElseIfComments();
+ isInComment = true;
+ i++;
+ if (!lineOpensWithComment) // does line start with comment?
+ blockCommentNoIndent = true; // if no, cannot indent continuation lines
+ continue;
+ }
+ else if ((isInComment || isInLineComment) && line.compare(i, 2, "*/") == 0)
+ {
+ size_t firstText = line.find_first_not_of(" \t");
+ // if there is a 'case' statement after these comments unindent by 1
+ // only if the ending comment is the first entry on the line
+ if (isCaseHeaderCommentIndent && firstText == i)
+ --indentCount;
+ // if this comment close starts the line, must check for else-if indent
+ // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
+ // if there is an 'else' after these comments a tempStacks indent is required
+ if (firstText == i)
+ {
+ if (isElseHeaderIndent && !lineOpensWithComment && !tempStacks->empty())
+ indentCount += adjustIndentCountForBreakElseIfComments();
+ }
+ isInComment = false;
+ i++;
+ blockCommentNoIndent = false; // ok to indent next comment
+ continue;
+ }
+ // treat indented preprocessor lines as a line comment
+ else if (line[0] == '#' && isIndentedPreprocessor(line, i))
+ {
+ isInLineComment = true;
+ }
+
+ if (isInLineComment)
+ {
+ // bypass rest of the comment up to the comment end
+ while (i + 1 < line.length())
+ i++;
+
+ continue;
+ }
+ if (isInComment)
+ {
+ // if there is a 'case' statement after these comments unindent by 1
+ if (!lineOpensWithComment && isCaseHeaderCommentIndent)
+ --indentCount;
+ // isElseHeaderIndent is set by ASFormatter if shouldBreakElseIfs is requested
+ // if there is an 'else' after these comments a tempStacks indent is required
+ if (!lineOpensWithComment && isElseHeaderIndent && !tempStacks->empty())
+ indentCount += adjustIndentCountForBreakElseIfComments();
+ // bypass rest of the comment up to the comment end
+ while (i + 1 < line.length()
+ && line.compare(i + 1, 2, "*/") != 0)
+ i++;
+
+ continue;
+ }
+
+ // if we have reached this far then we are NOT in a comment or string of special character...
+
+ if (probationHeader != nullptr)
+ {
+ if ((probationHeader == &AS_STATIC && ch == '{')
+ || (probationHeader == &AS_SYNCHRONIZED && ch == '('))
+ {
+ // insert the probation header as a new header
+ isInHeader = true;
+ headerStack->emplace_back(probationHeader);
+
+ // handle the specific probation header
+ isInConditional = (probationHeader == &AS_SYNCHRONIZED);
+
+ isContinuation = false;
+ // if the probation comes from the previous line, then indent by 1 tab count.
+ if (previousLineProbation
+ && ch == '{'
+ && !(blockIndent && probationHeader == &AS_STATIC))
+ {
+ ++indentCount;
+ previousLineProbationTab = true;
+ }
+ previousLineProbation = false;
+ }
+
+ // dismiss the probation header
+ probationHeader = nullptr;
+ }
+
+ prevNonSpaceCh = currentNonSpaceCh;
+ currentNonSpaceCh = ch;
+ if (!isLegalNameChar(ch) && ch != ',' && ch != ';')
+ {
+ prevNonLegalCh = currentNonLegalCh;
+ currentNonLegalCh = ch;
+ }
+
+ if (isInHeader)
+ {
+ isInHeader = false;
+ currentHeader = headerStack->back();
+ }
+ else
+ currentHeader = nullptr;
+
+ if (isCStyle() && isInTemplate
+ && (ch == '<' || ch == '>')
+ && !(line.length() > i + 1 && line.compare(i, 2, ">=") == 0))
+ {
+ if (ch == '<')
+ {
+ ++templateDepth;
+ continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
+ registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
+ }
+ else if (ch == '>')
+ {
+ popLastContinuationIndent();
+ if (--templateDepth <= 0)
+ {
+ ch = ';';
+ isInTemplate = false;
+ templateDepth = 0;
+ }
+ }
+ }
+
+ // handle parentheses
+ if (ch == '(' || ch == '[' || ch == ')' || ch == ']')
+ {
+ if (ch == '(' || ch == '[')
+ {
+ isInOperator = false;
+ // if have a struct header, this is a declaration not a definition
+ if (ch == '('
+ && !headerStack->empty()
+ && headerStack->back() == &AS_STRUCT)
+ {
+ headerStack->pop_back();
+ isInClassHeader = false;
+ if (line.find(AS_STRUCT, 0) > i) // if not on this line
+ indentCount -= classInitializerIndents;
+ if (indentCount < 0)
+ indentCount = 0;
+ }
+
+ if (parenDepth == 0)
+ {
+ parenStatementStack->push_back(isContinuation);
+ isContinuation = true;
+ }
+ parenDepth++;
+ if (ch == '[')
+ {
+ ++squareBracketCount;
+ if (squareBracketCount == 1 && isCStyle())
+ {
+ isInObjCMethodCall = true;
+ isInObjCMethodCallFirst = true;
+ }
+ }
+
+ continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
+
+ if (currentHeader != nullptr)
+ registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, minConditionalIndent, true);
+ else
+ registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
+ }
+ else if (ch == ')' || ch == ']')
+ {
+ if (ch == ']')
+ --squareBracketCount;
+ if (squareBracketCount <= 0)
+ {
+ squareBracketCount = 0;
+ if (isInObjCMethodCall)
+ isImmediatelyPostObjCMethodCall = true;
+ }
+ foundPreCommandHeader = false;
+ parenDepth--;
+ if (parenDepth == 0)
+ {
+ if (!parenStatementStack->empty()) // in case of unmatched closing parens
+ {
+ isContinuation = parenStatementStack->back();
+ parenStatementStack->pop_back();
+ }
+ isInAsm = false;
+ isInConditional = false;
+ }
+
+ if (!continuationIndentStackSizeStack->empty())
+ {
+ popLastContinuationIndent();
+
+ if (!parenIndentStack->empty())
+ {
+ int poppedIndent = parenIndentStack->back();
+ parenIndentStack->pop_back();
+
+ if (i == 0)
+ spaceIndentCount = poppedIndent;
+ }
+ }
+ }
+ continue;
+ }
+
+ if (ch == '{')
+ {
+ // first, check if '{' is a block-opener or a static-array opener
+ bool isBlockOpener = ((prevNonSpaceCh == '{' && braceBlockStateStack->back())
+ || prevNonSpaceCh == '}'
+ || prevNonSpaceCh == ')'
+ || prevNonSpaceCh == ';'
+ || peekNextChar(line, i) == '{'
+ || foundPreCommandHeader
+ || foundPreCommandMacro
+ || isInClassHeader
+ || (isInClassInitializer && !isLegalNameChar(prevNonSpaceCh))
+ || isNonInStatementArray
+ || isInObjCMethodDefinition
+ || isInObjCInterface
+ || isSharpAccessor
+ || isSharpDelegate
+ || isInExternC
+ || isInAsmBlock
+ || getNextWord(line, i) == AS_NEW
+ || (isInDefine
+ && (prevNonSpaceCh == '('
+ || isLegalNameChar(prevNonSpaceCh))));
+
+ if (isInObjCMethodDefinition)
+ {
+ objCColonAlignSubsequent = 0;
+ isImmediatelyPostObjCMethodDefinition = true;
+ if (lineBeginsWithOpenBrace) // for run-in braces
+ clearObjCMethodDefinitionAlignment();
+ }
+
+ if (!isBlockOpener && !isContinuation && !isInClassInitializer && !isInEnum)
+ {
+ if (headerStack->empty())
+ isBlockOpener = true;
+ else if (headerStack->back() == &AS_OPEN_BRACE
+ && headerStack->size() >= 2)
+ {
+ if ((*headerStack)[headerStack->size() - 2] == &AS_NAMESPACE
+ || (*headerStack)[headerStack->size() - 2] == &AS_MODULE
+ || (*headerStack)[headerStack->size() - 2] == &AS_CLASS
+ || (*headerStack)[headerStack->size() - 2] == &AS_INTERFACE
+ || (*headerStack)[headerStack->size() - 2] == &AS_STRUCT
+ || (*headerStack)[headerStack->size() - 2] == &AS_UNION)
+ isBlockOpener = true;
+ }
+ else if (headerStack->back() == &AS_NAMESPACE
+ || headerStack->back() == &AS_MODULE
+ || headerStack->back() == &AS_CLASS
+ || headerStack->back() == &AS_INTERFACE
+ || headerStack->back() == &AS_STRUCT
+ || headerStack->back() == &AS_UNION)
+ isBlockOpener = true;
+ }
+
+ if (!isBlockOpener && currentHeader != nullptr)
+ {
+ for (size_t n = 0; n < nonParenHeaders->size(); n++)
+ if (currentHeader == (*nonParenHeaders)[n])
+ {
+ isBlockOpener = true;
+ break;
+ }
+ }
+
+ braceBlockStateStack->push_back(isBlockOpener);
+
+ if (!isBlockOpener)
+ {
+ continuationIndentStackSizeStack->push_back(continuationIndentStack->size());
+ registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true);
+ parenDepth++;
+ if (i == 0)
+ shouldIndentBracedLine = false;
+ isInEnumTypeID = false;
+
+ continue;
+ }
+
+ // this brace is a block opener...
+
+ ++lineOpeningBlocksNum;
+
+ if (isInClassInitializer || isInEnumTypeID)
+ {
+ // decrease tab count if brace is broken
+ if (lineBeginsWithOpenBrace)
+ {
+ indentCount -= classInitializerIndents;
+ // decrease one more if an empty class
+ if (!headerStack->empty()
+ && (*headerStack).back() == &AS_CLASS)
+ {
+ int nextChar = getNextProgramCharDistance(line, i);
+ if ((int) line.length() > nextChar && line[nextChar] == '}')
+ --indentCount;
+ }
+ }
+ }
+
+ if (isInObjCInterface)
+ {
+ isInObjCInterface = false;
+ if (lineBeginsWithOpenBrace)
+ --indentCount;
+ }
+
+ if (braceIndent && !namespaceIndent && !headerStack->empty()
+ && ((*headerStack).back() == &AS_NAMESPACE
+ || (*headerStack).back() == &AS_MODULE))
+ {
+ shouldIndentBracedLine = false;
+ --indentCount;
+ }
+
+ // an indentable struct is treated like a class in the header stack
+ if (!headerStack->empty()
+ && (*headerStack).back() == &AS_STRUCT
+ && isInIndentableStruct)
+ (*headerStack).back() = &AS_CLASS;
+
+ squareBracketDepthStack->emplace_back(parenDepth);
+ blockStatementStack->push_back(isContinuation);
+
+ if (!continuationIndentStack->empty())
+ {
+ // completely purge the inStatementIndentStack
+ while (!continuationIndentStack->empty())
+ popLastContinuationIndent();
+ if (isInClassInitializer || isInClassHeaderTab)
+ {
+ if (lineBeginsWithOpenBrace || lineBeginsWithComma)
+ spaceIndentCount = 0;
+ }
+ else
+ spaceIndentCount = 0;
+ }
+
+ blockTabCount += (isContinuation ? 1 : 0);
+ if (g_preprocessorCppExternCBrace == 3)
+ ++g_preprocessorCppExternCBrace;
+ parenDepth = 0;
+ isInClassHeader = false;
+ isInClassHeaderTab = false;
+ isInClassInitializer = false;
+ isInEnumTypeID = false;
+ isContinuation = false;
+ isInQuestion = false;
+ isInLet = false;
+ foundPreCommandHeader = false;
+ foundPreCommandMacro = false;
+ isInExternC = false;
+
+ tempStacks->emplace_back(new vector<const string*>);
+ headerStack->emplace_back(&AS_OPEN_BRACE);
+ lastLineHeader = &AS_OPEN_BRACE;
+
+ continue;
+ } // end '{'
+
+ //check if a header has been reached
+ bool isPotentialHeader = isCharPotentialHeader(line, i);
+
+ if (isPotentialHeader && squareBracketCount == 0)
+ {
+ const string* newHeader = findHeader(line, i, headers);
+
+ // Qt headers may be variables in C++
+ if (isCStyle()
+ && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
+ {
+ if (line.find_first_of("=;", i) != string::npos)
+ newHeader = nullptr;
+ }
+ else if (newHeader == &AS_USING
+ && ASBeautifier::peekNextChar(line, i + (*newHeader).length() - 1) != '(')
+ newHeader = nullptr;
+
+ if (newHeader != nullptr)
+ {
+ // if we reached here, then this is a header...
+ bool isIndentableHeader = true;
+
+ isInHeader = true;
+
+ vector<const string*>* lastTempStack = nullptr;;
+ if (!tempStacks->empty())
+ lastTempStack = tempStacks->back();
+
+ // if a new block is opened, push a new stack into tempStacks to hold the
+ // future list of headers in the new block.
+
+ // take care of the special case: 'else if (...)'
+ if (newHeader == &AS_IF && lastLineHeader == &AS_ELSE)
+ {
+ headerStack->pop_back();
+ }
+
+ // take care of 'else'
+ else if (newHeader == &AS_ELSE)
+ {
+ if (lastTempStack != nullptr)
+ {
+ int indexOfIf = indexOf(*lastTempStack, &AS_IF);
+ if (indexOfIf != -1)
+ {
+ // recreate the header list in headerStack up to the previous 'if'
+ // from the temporary snapshot stored in lastTempStack.
+ int restackSize = lastTempStack->size() - indexOfIf - 1;
+ for (int r = 0; r < restackSize; r++)
+ {
+ headerStack->emplace_back(lastTempStack->back());
+ lastTempStack->pop_back();
+ }
+ if (!closingBraceReached)
+ indentCount += restackSize;
+ }
+ /*
+ * If the above if is not true, i.e. no 'if' before the 'else',
+ * then nothing beautiful will come out of this...
+ * I should think about inserting an Exception here to notify the caller of this...
+ */
+ }
+ }
+
+ // check if 'while' closes a previous 'do'
+ else if (newHeader == &AS_WHILE)
+ {
+ if (lastTempStack != nullptr)
+ {
+ int indexOfDo = indexOf(*lastTempStack, &AS_DO);
+ if (indexOfDo != -1)
+ {
+ // recreate the header list in headerStack up to the previous 'do'
+ // from the temporary snapshot stored in lastTempStack.
+ int restackSize = lastTempStack->size() - indexOfDo - 1;
+ for (int r = 0; r < restackSize; r++)
+ {
+ headerStack->emplace_back(lastTempStack->back());
+ lastTempStack->pop_back();
+ }
+ if (!closingBraceReached)
+ indentCount += restackSize;
+ }
+ }
+ }
+ // check if 'catch' closes a previous 'try' or 'catch'
+ else if (newHeader == &AS_CATCH || newHeader == &AS_FINALLY)
+ {
+ if (lastTempStack != nullptr)
+ {
+ int indexOfTry = indexOf(*lastTempStack, &AS_TRY);
+ if (indexOfTry == -1)
+ indexOfTry = indexOf(*lastTempStack, &AS_CATCH);
+ if (indexOfTry != -1)
+ {
+ // recreate the header list in headerStack up to the previous 'try'
+ // from the temporary snapshot stored in lastTempStack.
+ int restackSize = lastTempStack->size() - indexOfTry - 1;
+ for (int r = 0; r < restackSize; r++)
+ {
+ headerStack->emplace_back(lastTempStack->back());
+ lastTempStack->pop_back();
+ }
+
+ if (!closingBraceReached)
+ indentCount += restackSize;
+ }
+ }
+ }
+ else if (newHeader == &AS_CASE)
+ {
+ isInCase = true;
+ if (!haveCaseIndent)
+ {
+ haveCaseIndent = true;
+ if (!lineBeginsWithOpenBrace)
+ --indentCount;
+ }
+ }
+ else if (newHeader == &AS_DEFAULT)
+ {
+ isInCase = true;
+ --indentCount;
+ }
+ else if (newHeader == &AS_STATIC
+ || newHeader == &AS_SYNCHRONIZED)
+ {
+ if (!headerStack->empty()
+ && (headerStack->back() == &AS_STATIC
+ || headerStack->back() == &AS_SYNCHRONIZED))
+ {
+ isIndentableHeader = false;
+ }
+ else
+ {
+ isIndentableHeader = false;
+ probationHeader = newHeader;
+ }
+ }
+ else if (newHeader == &AS_TEMPLATE)
+ {
+ isInTemplate = true;
+ isIndentableHeader = false;
+ }
+
+ if (isIndentableHeader)
+ {
+ headerStack->emplace_back(newHeader);
+ isContinuation = false;
+ if (indexOf(*nonParenHeaders, newHeader) == -1)
+ {
+ isInConditional = true;
+ }
+ lastLineHeader = newHeader;
+ }
+ else
+ isInHeader = false;
+
+ i += newHeader->length() - 1;
+
+ continue;
+ } // newHeader != nullptr
+
+ if (findHeader(line, i, preCommandHeaders) != nullptr)
+ foundPreCommandHeader = true;
+
+ // Objective-C NSException macros are preCommandHeaders
+ if (isCStyle() && findKeyword(line, i, AS_NS_DURING))
+ foundPreCommandMacro = true;
+ if (isCStyle() && findKeyword(line, i, AS_NS_HANDLER))
+ foundPreCommandMacro = true;
+
+ if (parenDepth == 0 && findKeyword(line, i, AS_ENUM))
+ isInEnum = true;
+
+ if (isSharpStyle() && findKeyword(line, i, AS_LET))
+ isInLet = true;
+
+ } // isPotentialHeader
+
+ if (ch == '?')
+ isInQuestion = true;
+
+ // special handling of colons
+ if (ch == ':')
+ {
+ if (line.length() > i + 1 && line[i + 1] == ':') // look for ::
+ {
+ ++i;
+ continue;
+ }
+ else if (isInQuestion)
+ {
+ // do nothing special
+ }
+ else if (parenDepth > 0)
+ {
+ // found a 'for' loop or an objective-C statement
+ // so do nothing special
+ }
+ else if (isInEnum)
+ {
+ // found an enum with a base-type
+ isInEnumTypeID = true;
+ if (i == 0)
+ indentCount += classInitializerIndents;
+ }
+ else if (isCStyle()
+ && !isInCase
+ && (prevNonSpaceCh == ')' || foundPreCommandHeader))
+ {
+ // found a 'class' c'tor initializer
+ isInClassInitializer = true;
+ registerContinuationIndentColon(line, i, tabIncrementIn);
+ if (i == 0)
+ indentCount += classInitializerIndents;
+ }
+ else if (isInClassHeader || isInObjCInterface)
+ {
+ // is in a 'class A : public B' definition
+ isInClassHeaderTab = true;
+ registerContinuationIndentColon(line, i, tabIncrementIn);
+ }
+ else if (isInAsm || isInAsmOneLine || isInAsmBlock)
+ {
+ // do nothing special
+ }
+ else if (isDigit(peekNextChar(line, i)))
+ {
+ // found a bit field - do nothing special
+ }
+ else if (isCStyle() && isInClass && prevNonSpaceCh != ')')
+ {
+ // found a 'private:' or 'public:' inside a class definition
+ --indentCount;
+ if (modifierIndent)
+ spaceIndentCount += (indentLength / 2);
+ }
+ else if (isCStyle() && !isInClass
+ && headerStack->size() >= 2
+ && (*headerStack)[headerStack->size() - 2] == &AS_CLASS
+ && (*headerStack)[headerStack->size() - 1] == &AS_OPEN_BRACE)
+ {
+ // found a 'private:' or 'public:' inside a class definition
+ // and on the same line as the class opening brace
+ // do nothing
+ }
+ else if (isJavaStyle() && lastLineHeader == &AS_FOR)
+ {
+ // found a java for-each statement
+ // so do nothing special
+ }
+ else
+ {
+ currentNonSpaceCh = ';'; // so that braces after the ':' will appear as block-openers
+ char peekedChar = peekNextChar(line, i);
+ if (isInCase)
+ {
+ isInCase = false;
+ ch = ';'; // from here on, treat char as ';'
+ }
+ else if (isCStyle() || (isSharpStyle() && peekedChar == ';'))
+ {
+ // is in a label (e.g. 'label1:')
+ if (labelIndent)
+ --indentCount; // unindent label by one indent
+ else if (!lineBeginsWithOpenBrace)
+ indentCount = 0; // completely flush indent to left
+ }
+ }
+ }
+
+ if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !continuationIndentStackSizeStack->empty())
+ while ((int) continuationIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0)
+ < (int) continuationIndentStack->size())
+ continuationIndentStack->pop_back();
+
+ else if (ch == ',' && isInEnum && isNonInStatementArray && !continuationIndentStack->empty())
+ continuationIndentStack->pop_back();
+
+ // handle commas
+ // previous "isInStatement" will be from an assignment operator or class initializer
+ if (ch == ',' && parenDepth == 0 && !isContinuation && !isNonInStatementArray)
+ {
+ // is comma at end of line
+ size_t nextChar = line.find_first_not_of(" \t", i + 1);
+ if (nextChar != string::npos)
+ {
+ if (line.compare(nextChar, 2, "//") == 0
+ || line.compare(nextChar, 2, "/*") == 0)
+ nextChar = string::npos;
+ }
+ // register indent
+ if (nextChar == string::npos)
+ {
+ // register indent at previous word
+ if (isJavaStyle() && isInClassHeader)
+ {
+ // do nothing for now
+ }
+ // register indent at second word on the line
+ else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer)
+ {
+ int prevWord = getContinuationIndentComma(line, i);
+ int continuationIndentCount = prevWord + spaceIndentCount + tabIncrementIn;
+ continuationIndentStack->emplace_back(continuationIndentCount);
+ isContinuation = true;
+ }
+ }
+ }
+ // handle comma first initializers
+ if (ch == ',' && parenDepth == 0 && lineBeginsWithComma
+ && (isInClassInitializer || isInClassHeaderTab))
+ spaceIndentCount = 0;
+
+ // handle ends of statements
+ if ((ch == ';' && parenDepth == 0) || ch == '}')
+ {
+ if (ch == '}')
+ {
+ // first check if this '}' closes a previous block, or a static array...
+ if (braceBlockStateStack->size() > 1)
+ {
+ bool braceBlockState = braceBlockStateStack->back();
+ braceBlockStateStack->pop_back();
+ if (!braceBlockState)
+ {
+ if (!continuationIndentStackSizeStack->empty())
+ {
+ // this brace is a static array
+ popLastContinuationIndent();
+ parenDepth--;
+ if (i == 0)
+ shouldIndentBracedLine = false;
+
+ if (!parenIndentStack->empty())
+ {
+ int poppedIndent = parenIndentStack->back();
+ parenIndentStack->pop_back();
+ if (i == 0)
+ spaceIndentCount = poppedIndent;
+ }
+ }
+ continue;
+ }
+ }
+
+ // this brace is block closer...
+
+ ++lineClosingBlocksNum;
+
+ if (!continuationIndentStackSizeStack->empty())
+ popLastContinuationIndent();
+
+ if (!squareBracketDepthStack->empty())
+ {
+ parenDepth = squareBracketDepthStack->back();
+ squareBracketDepthStack->pop_back();
+ isContinuation = blockStatementStack->back();
+ blockStatementStack->pop_back();
+
+ if (isContinuation)
+ blockTabCount--;
+ }
+
+ closingBraceReached = true;
+ if (i == 0)
+ spaceIndentCount = 0;
+ isInAsmBlock = false;
+ isInAsm = isInAsmOneLine = isInQuote = false; // close these just in case
+
+ int headerPlace = indexOf(*headerStack, &AS_OPEN_BRACE);
+ if (headerPlace != -1)
+ {
+ const string* popped = headerStack->back();
+ while (popped != &AS_OPEN_BRACE)
+ {
+ headerStack->pop_back();
+ popped = headerStack->back();
+ }
+ headerStack->pop_back();
+
+ if (headerStack->empty())
+ g_preprocessorCppExternCBrace = 0;
+
+ // do not indent namespace brace unless namespaces are indented
+ if (!namespaceIndent && !headerStack->empty()
+ && ((*headerStack).back() == &AS_NAMESPACE
+ || (*headerStack).back() == &AS_MODULE)
+ && i == 0) // must be the first brace on the line
+ shouldIndentBracedLine = false;
+
+ if (!tempStacks->empty())
+ {
+ vector<const string*>* temp = tempStacks->back();
+ tempStacks->pop_back();
+ delete temp;
+ }
+ }
+
+ ch = ' '; // needed due to cases such as '}else{', so that headers ('else' in this case) will be identified...
+ } // ch == '}'
+
+ /*
+ * Create a temporary snapshot of the current block's header-list in the
+ * uppermost inner stack in tempStacks, and clear the headerStack up to
+ * the beginning of the block.
+ * Thus, the next future statement will think it comes one indent past
+ * the block's '{' unless it specifically checks for a companion-header
+ * (such as a previous 'if' for an 'else' header) within the tempStacks,
+ * and recreates the temporary snapshot by manipulating the tempStacks.
+ */
+ if (!tempStacks->back()->empty())
+ while (!tempStacks->back()->empty())
+ tempStacks->back()->pop_back();
+ while (!headerStack->empty() && headerStack->back() != &AS_OPEN_BRACE)
+ {
+ tempStacks->back()->emplace_back(headerStack->back());
+ headerStack->pop_back();
+ }
+
+ if (parenDepth == 0 && ch == ';')
+ isContinuation = false;
+
+ if (isInObjCMethodDefinition)
+ {
+ objCColonAlignSubsequent = 0;
+ isImmediatelyPostObjCMethodDefinition = true;
+ }
+
+ previousLastLineHeader = nullptr;
+ isInClassHeader = false; // for 'friend' class
+ isInEnum = false;
+ isInEnumTypeID = false;
+ isInQuestion = false;
+ isInTemplate = false;
+ isInObjCInterface = false;
+ foundPreCommandHeader = false;
+ foundPreCommandMacro = false;
+ squareBracketCount = 0;
+
+ continue;
+ }
+
+ if (isPotentialHeader)
+ {
+ // check for preBlockStatements in C/C++ ONLY if not within parentheses
+ // (otherwise 'struct XXX' statements would be wrongly interpreted...)
+ if (!isInTemplate && !(isCStyle() && parenDepth > 0))
+ {
+ const string* newHeader = findHeader(line, i, preBlockStatements);
+ // handle CORBA IDL module
+ if (newHeader == &AS_MODULE)
+ {
+ char nextChar = peekNextChar(line, i + newHeader->length() - 1);
+ if (prevNonSpaceCh == ')' || !isalpha(nextChar))
+ newHeader = nullptr;
+ }
+ if (newHeader != nullptr
+ && !(isCStyle() && newHeader == &AS_CLASS && isInEnum)) // is not 'enum class'
+ {
+ if (!isSharpStyle())
+ headerStack->emplace_back(newHeader);
+ // do not need 'where' in the headerStack
+ // do not need second 'class' statement in a row
+ else if (!(newHeader == &AS_WHERE
+ || ((newHeader == &AS_CLASS || newHeader == &AS_STRUCT)
+ && !headerStack->empty()
+ && (headerStack->back() == &AS_CLASS
+ || headerStack->back() == &AS_STRUCT))))
+ headerStack->emplace_back(newHeader);
+
+ if (!headerStack->empty())
+ {
+ if ((*headerStack).back() == &AS_CLASS
+ || (*headerStack).back() == &AS_STRUCT
+ || (*headerStack).back() == &AS_INTERFACE)
+ {
+ isInClassHeader = true;
+ }
+ else if ((*headerStack).back() == &AS_NAMESPACE
+ || (*headerStack).back() == &AS_MODULE)
+ {
+ // remove continuationIndent from namespace
+ if (!continuationIndentStack->empty())
+ continuationIndentStack->pop_back();
+ isContinuation = false;
+ }
+ }
+
+ i += newHeader->length() - 1;
+ continue;
+ }
+ }
+ const string* foundIndentableHeader = findHeader(line, i, indentableHeaders);
+
+ if (foundIndentableHeader != nullptr)
+ {
+ // must bypass the header before registering the in statement
+ i += foundIndentableHeader->length() - 1;
+ if (!isInOperator && !isInTemplate && !isNonInStatementArray)
+ {
+ registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
+ isContinuation = true;
+ }
+ continue;
+ }
+
+ if (isCStyle() && findKeyword(line, i, AS_OPERATOR))
+ isInOperator = true;
+
+ if (g_preprocessorCppExternCBrace == 1 && findKeyword(line, i, AS_EXTERN))
+ ++g_preprocessorCppExternCBrace;
+
+ if (g_preprocessorCppExternCBrace == 3) // extern "C" is not followed by a '{'
+ g_preprocessorCppExternCBrace = 0;
+
+ // "new" operator is a pointer, not a calculation
+ if (findKeyword(line, i, AS_NEW))
+ {
+ if (isContinuation && !continuationIndentStack->empty() && prevNonSpaceCh == '=')
+ continuationIndentStack->back() = 0;
+ }
+
+ if (isCStyle())
+ {
+ if (findKeyword(line, i, AS_ASM)
+ || findKeyword(line, i, AS__ASM__))
+ {
+ isInAsm = true;
+ }
+ else if (findKeyword(line, i, AS_MS_ASM) // microsoft specific
+ || findKeyword(line, i, AS_MS__ASM))
+ {
+ int index = 4;
+ if (peekNextChar(line, i) == '_') // check for __asm
+ index = 5;
+
+ char peekedChar = peekNextChar(line, i + index);
+ if (peekedChar == '{' || peekedChar == ' ')
+ isInAsmBlock = true;
+ else
+ isInAsmOneLine = true;
+ }
+ }
+
+ // bypass the entire name for all others
+ string name = getCurrentWord(line, i);
+ i += name.length() - 1;
+ continue;
+ }
+
+ // Handle Objective-C statements
+
+ if (ch == '@' && !isWhiteSpace(line[i + 1])
+ && isCharPotentialHeader(line, i + 1))
+ {
+ string curWord = getCurrentWord(line, i + 1);
+ if (curWord == AS_INTERFACE && headerStack->empty())
+ {
+ isInObjCInterface = true;
+ string name = '@' + curWord;
+ i += name.length() - 1;
+ continue;
+ }
+ else if (isInObjCInterface)
+ {
+ --indentCount;
+ isInObjCInterface = false;
+ }
+
+ if (curWord == AS_PUBLIC
+ || curWord == AS_PRIVATE
+ || curWord == AS_PROTECTED)
+ {
+ --indentCount;
+ if (modifierIndent)
+ spaceIndentCount += (indentLength / 2);
+ string name = '@' + curWord;
+ i += name.length() - 1;
+ continue;
+ }
+ else if (curWord == AS_END)
+ {
+ popLastContinuationIndent();
+ spaceIndentCount = 0;
+ isInObjCMethodDefinition = false;
+ string name = '@' + curWord;
+ i += name.length() - 1;
+ continue;
+ }
+ }
+ else if ((ch == '-' || ch == '+')
+ && peekNextChar(line, i) == '('
+ && headerStack->empty()
+ && line.find_first_not_of(" \t") == i)
+ {
+ if (isInObjCInterface)
+ --indentCount;
+ isInObjCInterface = false;
+ isInObjCMethodDefinition = true;
+ continue;
+ }
+
+ // Handle operators
+
+ bool isPotentialOperator = isCharPotentialOperator(ch);
+
+ if (isPotentialOperator)
+ {
+ // Check if an operator has been reached.
+ const string* foundAssignmentOp = findOperator(line, i, assignmentOperators);
+ const string* foundNonAssignmentOp = findOperator(line, i, nonAssignmentOperators);
+
+ if (foundNonAssignmentOp != nullptr)
+ {
+ if (foundNonAssignmentOp == &AS_LAMBDA)
+ foundPreCommandHeader = true;
+ if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR)
+ foundNonAssignmentOp = nullptr;
+ }
+
+ // Since findHeader's boundary checking was not used above, it is possible
+ // that both an assignment op and a non-assignment op where found,
+ // e.g. '>>' and '>>='. If this is the case, treat the LONGER one as the
+ // found operator.
+ if (foundAssignmentOp != nullptr && foundNonAssignmentOp != nullptr)
+ {
+ if (foundAssignmentOp->length() < foundNonAssignmentOp->length())
+ foundAssignmentOp = nullptr;
+ else
+ foundNonAssignmentOp = nullptr;
+ }
+
+ if (foundNonAssignmentOp != nullptr)
+ {
+ if (foundNonAssignmentOp->length() > 1)
+ i += foundNonAssignmentOp->length() - 1;
+
+ // For C++ input/output, operator<< and >> should be
+ // aligned, if we are not in a statement already and
+ // also not in the "operator<<(...)" header line
+ if (!isInOperator
+ && continuationIndentStack->empty()
+ && isCStyle()
+ && (foundNonAssignmentOp == &AS_GR_GR
+ || foundNonAssignmentOp == &AS_LS_LS))
+ {
+ // this will be true if the line begins with the operator
+ if (i < 2 && spaceIndentCount == 0)
+ spaceIndentCount += 2 * indentLength;
+ // align to the beginning column of the operator
+ registerContinuationIndent(line, i - foundNonAssignmentOp->length(), spaceIndentCount, tabIncrementIn, 0, false);
+ }
+ }
+
+ else if (foundAssignmentOp != nullptr)
+ {
+ foundPreCommandHeader = false; // clears this for array assignments
+ foundPreCommandMacro = false;
+
+ if (foundAssignmentOp->length() > 1)
+ i += foundAssignmentOp->length() - 1;
+
+ if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum))
+ {
+ // if multiple assignments, align on the previous word
+ if (foundAssignmentOp == &AS_ASSIGN
+ && prevNonSpaceCh != ']' // an array
+ && statementEndsWithComma(line, i))
+ {
+ if (!haveAssignmentThisLine) // only one assignment indent per line
+ {
+ // register indent at previous word
+ haveAssignmentThisLine = true;
+ int prevWordIndex = getContinuationIndentAssign(line, i);
+ int continuationIndentCount = prevWordIndex + spaceIndentCount + tabIncrementIn;
+ continuationIndentStack->emplace_back(continuationIndentCount);
+ isContinuation = true;
+ }
+ }
+ // don't indent an assignment if 'let'
+ else if (isInLet)
+ {
+ isInLet = false;
+ }
+ else if (!lineBeginsWithComma)
+ {
+ if (i == 0 && spaceIndentCount == 0)
+ spaceIndentCount += indentLength;
+ registerContinuationIndent(line, i, spaceIndentCount, tabIncrementIn, 0, false);
+ isContinuation = true;
+ }
+ }
+ }
+ }
+ } // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop *
+}
+
+} // end namespace astyle
--- /dev/null
+// ASEnhancer.cpp
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+
+//-----------------------------------------------------------------------------
+// headers
+//-----------------------------------------------------------------------------
+
+#include "astyle.h"
+
+//-----------------------------------------------------------------------------
+// astyle namespace
+//-----------------------------------------------------------------------------
+
+namespace astyle {
+//
+//-----------------------------------------------------------------------------
+// ASEnhancer class
+//-----------------------------------------------------------------------------
+
+/**
+ * ASEnhancer constructor
+ */
+ASEnhancer::ASEnhancer()
+{
+}
+
+/**
+ * Destructor of ASEnhancer
+ */
+ASEnhancer::~ASEnhancer()
+{
+}
+
+/**
+ * initialize the ASEnhancer.
+ *
+ * init() is called each time an ASFormatter object is initialized.
+ */
+void ASEnhancer::init(int _fileType,
+ int _indentLength,
+ int _tabLength,
+ bool _useTabs,
+ bool _forceTab,
+ bool _namespaceIndent,
+ bool _caseIndent,
+ bool _preprocBlockIndent,
+ bool _preprocDefineIndent,
+ bool _emptyLineFill,
+ vector<const pair<const string, const string>* >* _indentableMacros)
+{
+ // formatting variables from ASFormatter and ASBeautifier
+ ASBase::init(_fileType);
+ indentLength = _indentLength;
+ tabLength = _tabLength;
+ useTabs = _useTabs;
+ forceTab = _forceTab;
+ namespaceIndent = _namespaceIndent;
+ caseIndent = _caseIndent;
+ preprocBlockIndent = _preprocBlockIndent;
+ preprocDefineIndent = _preprocDefineIndent;
+ emptyLineFill = _emptyLineFill;
+ indentableMacros = _indentableMacros;
+ quoteChar = '\'';
+
+ // unindent variables
+ lineNumber = 0;
+ braceCount = 0;
+ isInComment = false;
+ isInQuote = false;
+ switchDepth = 0;
+ eventPreprocDepth = 0;
+ lookingForCaseBrace = false;
+ unindentNextLine = false;
+ shouldUnindentLine = false;
+ shouldUnindentComment = false;
+
+ // switch struct and vector
+ sw.switchBraceCount = 0;
+ sw.unindentDepth = 0;
+ sw.unindentCase = false;
+ switchStack.clear();
+
+ // other variables
+ nextLineIsEventIndent = false;
+ isInEventTable = false;
+ nextLineIsDeclareIndent = false;
+ isInDeclareSection = false;
+}
+
+/**
+ * additional formatting for line of source code.
+ * every line of source code in a source code file should be sent
+ * one after the other to this function.
+ * indents event tables
+ * unindents the case blocks
+ *
+ * @param line the original formatted line will be updated if necessary.
+ */
+void ASEnhancer::enhance(string& line, bool isInNamespace, bool isInPreprocessor, bool isInSQL)
+{
+ shouldUnindentLine = true;
+ shouldUnindentComment = false;
+ lineNumber++;
+
+ // check for beginning of event table
+ if (nextLineIsEventIndent)
+ {
+ isInEventTable = true;
+ nextLineIsEventIndent = false;
+ }
+
+ // check for beginning of SQL declare section
+ if (nextLineIsDeclareIndent)
+ {
+ isInDeclareSection = true;
+ nextLineIsDeclareIndent = false;
+ }
+
+ if (line.length() == 0
+ && !isInEventTable
+ && !isInDeclareSection
+ && !emptyLineFill)
+ return;
+
+ // test for unindent on attached braces
+ if (unindentNextLine)
+ {
+ sw.unindentDepth++;
+ sw.unindentCase = true;
+ unindentNextLine = false;
+ }
+
+ // parse characters in the current line
+ parseCurrentLine(line, isInPreprocessor, isInSQL);
+
+ // check for SQL indentable lines
+ if (isInDeclareSection)
+ {
+ size_t firstText = line.find_first_not_of(" \t");
+ if (firstText == string::npos || line[firstText] != '#')
+ indentLine(line, 1);
+ }
+
+ // check for event table indentable lines
+ if (isInEventTable
+ && (eventPreprocDepth == 0
+ || (namespaceIndent && isInNamespace)))
+ {
+ size_t firstText = line.find_first_not_of(" \t");
+ if (firstText == string::npos || line[firstText] != '#')
+ indentLine(line, 1);
+ }
+
+ if (shouldUnindentComment && sw.unindentDepth > 0)
+ unindentLine(line, sw.unindentDepth - 1);
+ else if (shouldUnindentLine && sw.unindentDepth > 0)
+ unindentLine(line, sw.unindentDepth);
+}
+
+/**
+ * convert a force-tab indent to spaces
+ *
+ * @param line a reference to the line that will be converted.
+ */
+void ASEnhancer::convertForceTabIndentToSpaces(string& line) const
+{
+ // replace tab indents with spaces
+ for (size_t i = 0; i < line.length(); i++)
+ {
+ if (!isWhiteSpace(line[i]))
+ break;
+ if (line[i] == '\t')
+ {
+ line.erase(i, 1);
+ line.insert(i, tabLength, ' ');
+ i += tabLength - 1;
+ }
+ }
+}
+
+/**
+ * convert a space indent to force-tab
+ *
+ * @param line a reference to the line that will be converted.
+ */
+void ASEnhancer::convertSpaceIndentToForceTab(string& line) const
+{
+ assert(tabLength > 0);
+
+ // replace leading spaces with tab indents
+ size_t newSpaceIndentLength = line.find_first_not_of(" \t");
+ size_t tabCount = newSpaceIndentLength / tabLength; // truncate extra spaces
+ line.replace(0U, tabCount * tabLength, tabCount, '\t');
+}
+
+/**
+ * find the colon following a 'case' statement
+ *
+ * @param line a reference to the line.
+ * @param caseIndex the line index of the case statement.
+ * @return the line index of the colon.
+ */
+size_t ASEnhancer::findCaseColon(const string& line, size_t caseIndex) const
+{
+ size_t i = caseIndex;
+ bool isInQuote_ = false;
+ char quoteChar_ = ' ';
+ for (; i < line.length(); i++)
+ {
+ if (isInQuote_)
+ {
+ if (line[i] == '\\')
+ {
+ i++;
+ continue;
+ }
+ else if (line[i] == quoteChar_) // check ending quote
+ {
+ isInQuote_ = false;
+ quoteChar_ = ' ';
+ continue;
+ }
+ else
+ {
+ continue; // must close quote before continuing
+ }
+ }
+ if (line[i] == '"' // check opening quote
+ || (line[i] == '\'' && !isDigitSeparator(line, i)))
+ {
+ isInQuote_ = true;
+ quoteChar_ = line[i];
+ continue;
+ }
+ if (line[i] == ':')
+ {
+ if ((i + 1 < line.length()) && (line[i + 1] == ':'))
+ i++; // bypass scope resolution operator
+ else
+ break; // found it
+ }
+ }
+ return i;
+}
+
+/**
+* indent a line by a given number of tabsets
+ * by inserting leading whitespace to the line argument.
+ *
+ * @param line a reference to the line to indent.
+ * @param indent the number of tabsets to insert.
+ * @return the number of characters inserted.
+ */
+int ASEnhancer::indentLine(string& line, int indent) const
+{
+ if (line.length() == 0
+ && !emptyLineFill)
+ return 0;
+
+ size_t charsToInsert = 0;
+
+ if (forceTab && indentLength != tabLength)
+ {
+ // replace tab indents with spaces
+ convertForceTabIndentToSpaces(line);
+ // insert the space indents
+ charsToInsert = indent * indentLength;
+ line.insert(line.begin(), charsToInsert, ' ');
+ // replace leading spaces with tab indents
+ convertSpaceIndentToForceTab(line);
+ }
+ else if (useTabs)
+ {
+ charsToInsert = indent;
+ line.insert(line.begin(), charsToInsert, '\t');
+ }
+ else // spaces
+ {
+ charsToInsert = indent * indentLength;
+ line.insert(line.begin(), charsToInsert, ' ');
+ }
+
+ return charsToInsert;
+}
+
+/**
+ * check for SQL "BEGIN DECLARE SECTION".
+ * must compare case insensitive and allow any spacing between words.
+ *
+ * @param line a reference to the line to indent.
+ * @param index the current line index.
+ * @return true if a hit.
+ */
+bool ASEnhancer::isBeginDeclareSectionSQL(const string& line, size_t index) const
+{
+ string word;
+ size_t hits = 0;
+ size_t i;
+ for (i = index; i < line.length(); i++)
+ {
+ i = line.find_first_not_of(" \t", i);
+ if (i == string::npos)
+ return false;
+ if (line[i] == ';')
+ break;
+ if (!isCharPotentialHeader(line, i))
+ continue;
+ word = getCurrentWord(line, i);
+ for (size_t j = 0; j < word.length(); j++)
+ word[j] = (char) toupper(word[j]);
+ if (word == "EXEC" || word == "SQL")
+ {
+ i += word.length() - 1;
+ continue;
+ }
+ if (word == "DECLARE" || word == "SECTION")
+ {
+ hits++;
+ i += word.length() - 1;
+ continue;
+ }
+ if (word == "BEGIN")
+ {
+ hits++;
+ i += word.length() - 1;
+ continue;
+ }
+ return false;
+ }
+ if (hits == 3)
+ return true;
+ return false;
+}
+
+/**
+ * check for SQL "END DECLARE SECTION".
+ * must compare case insensitive and allow any spacing between words.
+ *
+ * @param line a reference to the line to indent.
+ * @param index the current line index.
+ * @return true if a hit.
+ */
+bool ASEnhancer::isEndDeclareSectionSQL(const string& line, size_t index) const
+{
+ string word;
+ size_t hits = 0;
+ size_t i;
+ for (i = index; i < line.length(); i++)
+ {
+ i = line.find_first_not_of(" \t", i);
+ if (i == string::npos)
+ return false;
+ if (line[i] == ';')
+ break;
+ if (!isCharPotentialHeader(line, i))
+ continue;
+ word = getCurrentWord(line, i);
+ for (size_t j = 0; j < word.length(); j++)
+ word[j] = (char) toupper(word[j]);
+ if (word == "EXEC" || word == "SQL")
+ {
+ i += word.length() - 1;
+ continue;
+ }
+ if (word == "DECLARE" || word == "SECTION")
+ {
+ hits++;
+ i += word.length() - 1;
+ continue;
+ }
+ if (word == "END")
+ {
+ hits++;
+ i += word.length() - 1;
+ continue;
+ }
+ return false;
+ }
+ if (hits == 3)
+ return true;
+ return false;
+}
+
+/**
+ * check if a one-line brace has been reached,
+ * i.e. if the currently reached '{' character is closed
+ * with a complimentary '}' elsewhere on the current line,
+ *.
+ * @return false = one-line brace has not been reached.
+ * true = one-line brace has been reached.
+ */
+bool ASEnhancer::isOneLineBlockReached(const string& line, int startChar) const
+{
+ assert(line[startChar] == '{');
+
+ bool isInComment_ = false;
+ bool isInQuote_ = false;
+ int _braceCount = 1;
+ int lineLength = line.length();
+ char quoteChar_ = ' ';
+ char ch = ' ';
+
+ for (int i = startChar + 1; i < lineLength; ++i)
+ {
+ 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 == '\'' && !isDigitSeparator(line, i)))
+ {
+ isInQuote_ = true;
+ quoteChar_ = ch;
+ continue;
+ }
+
+ if (line.compare(i, 2, "//") == 0)
+ break;
+
+ if (line.compare(i, 2, "/*") == 0)
+ {
+ isInComment_ = true;
+ ++i;
+ continue;
+ }
+
+ if (ch == '{')
+ ++_braceCount;
+ else if (ch == '}')
+ --_braceCount;
+
+ if (_braceCount == 0)
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * parse characters in the current line to determine if an indent
+ * or unindent is needed.
+ */
+void ASEnhancer::parseCurrentLine(string& line, bool isInPreprocessor, bool isInSQL)
+{
+ bool isSpecialChar = false; // is a backslash escape character
+
+ for (size_t i = 0; i < line.length(); i++)
+ {
+ char ch = line[i];
+
+ // bypass whitespace
+ if (isWhiteSpace(ch))
+ continue;
+
+ // handle special characters (i.e. backslash+character such as \n, \t, ...)
+ if (isSpecialChar)
+ {
+ isSpecialChar = false;
+ continue;
+ }
+ if (!(isInComment) && line.compare(i, 2, "\\\\") == 0)
+ {
+ i++;
+ continue;
+ }
+ if (!(isInComment) && ch == '\\')
+ {
+ isSpecialChar = true;
+ continue;
+ }
+
+ // handle quotes (such as 'x' and "Hello Dolly")
+ if (!isInComment
+ && (ch == '"'
+ || (ch == '\'' && !isDigitSeparator(line, i))))
+ {
+ if (!isInQuote)
+ {
+ quoteChar = ch;
+ isInQuote = true;
+ }
+ else if (quoteChar == ch)
+ {
+ isInQuote = false;
+ continue;
+ }
+ }
+
+ if (isInQuote)
+ continue;
+
+ // handle comments
+
+ if (!(isInComment) && line.compare(i, 2, "//") == 0)
+ {
+ // check for windows line markers
+ if (line.compare(i + 2, 1, "\xf0") > 0)
+ lineNumber--;
+ // unindent if not in case braces
+ if (line.find_first_not_of(" \t") == i
+ && sw.switchBraceCount == 1
+ && sw.unindentCase)
+ shouldUnindentComment = true;
+ break; // finished with the line
+ }
+ else if (!(isInComment) && line.compare(i, 2, "/*") == 0)
+ {
+ // unindent if not in case braces
+ if (sw.switchBraceCount == 1 && sw.unindentCase)
+ shouldUnindentComment = true;
+ isInComment = true;
+ size_t commentEnd = line.find("*/", i);
+ if (commentEnd == string::npos)
+ i = line.length() - 1;
+ else
+ i = commentEnd - 1;
+ continue;
+ }
+ else if ((isInComment) && line.compare(i, 2, "*/") == 0)
+ {
+ // unindent if not in case braces
+ if (sw.switchBraceCount == 1 && sw.unindentCase)
+ shouldUnindentComment = true;
+ isInComment = false;
+ i++;
+ continue;
+ }
+
+ if (isInComment)
+ {
+ // unindent if not in case braces
+ if (sw.switchBraceCount == 1 && sw.unindentCase)
+ shouldUnindentComment = true;
+ size_t commentEnd = line.find("*/", i);
+ if (commentEnd == string::npos)
+ i = line.length() - 1;
+ else
+ i = commentEnd - 1;
+ continue;
+ }
+
+ // if we have reached this far then we are NOT in a comment or string of special characters
+
+ if (line[i] == '{')
+ braceCount++;
+
+ if (line[i] == '}')
+ braceCount--;
+
+ // check for preprocessor within an event table
+ if (isInEventTable && line[i] == '#' && preprocBlockIndent)
+ {
+ string preproc;
+ preproc = line.substr(i + 1);
+ if (preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef)
+ eventPreprocDepth += 1;
+ if (preproc.substr(0, 5) == "endif" && eventPreprocDepth > 0)
+ eventPreprocDepth -= 1;
+ }
+
+ bool isPotentialKeyword = isCharPotentialHeader(line, i);
+
+ // ---------------- wxWidgets and MFC macros ----------------------------------
+
+ if (isPotentialKeyword)
+ {
+ for (size_t j = 0; j < indentableMacros->size(); j++)
+ {
+ // 'first' is the beginning macro
+ if (findKeyword(line, i, indentableMacros->at(j)->first))
+ {
+ nextLineIsEventIndent = true;
+ break;
+ }
+ }
+ for (size_t j = 0; j < indentableMacros->size(); j++)
+ {
+ // 'second' is the ending macro
+ if (findKeyword(line, i, indentableMacros->at(j)->second))
+ {
+ isInEventTable = false;
+ eventPreprocDepth = 0;
+ break;
+ }
+ }
+ }
+
+ // ---------------- process SQL -----------------------------------------------
+
+ if (isInSQL)
+ {
+ if (isBeginDeclareSectionSQL(line, i))
+ nextLineIsDeclareIndent = true;
+ if (isEndDeclareSectionSQL(line, i))
+ isInDeclareSection = false;
+ break;
+ }
+
+ // ---------------- process switch statements ---------------------------------
+
+ if (isPotentialKeyword && findKeyword(line, i, ASResource::AS_SWITCH))
+ {
+ switchDepth++;
+ switchStack.emplace_back(sw); // save current variables
+ sw.switchBraceCount = 0;
+ sw.unindentCase = false; // don't clear case until end of switch
+ i += 5; // bypass switch statement
+ continue;
+ }
+
+ // just want unindented case statements from this point
+
+ if (caseIndent
+ || switchDepth == 0
+ || (isInPreprocessor && !preprocDefineIndent))
+ {
+ // bypass the entire word
+ if (isPotentialKeyword)
+ {
+ string name = getCurrentWord(line, i);
+ i += name.length() - 1;
+ }
+ continue;
+ }
+
+ i = processSwitchBlock(line, i);
+
+ } // end of for loop * end of for loop * end of for loop * end of for loop
+}
+
+/**
+ * process the character at the current index in a switch block.
+ *
+ * @param line a reference to the line to indent.
+ * @param index the current line index.
+ * @return the new line index.
+ */
+size_t ASEnhancer::processSwitchBlock(string& line, size_t index)
+{
+ size_t i = index;
+ bool isPotentialKeyword = isCharPotentialHeader(line, i);
+
+ if (line[i] == '{')
+ {
+ sw.switchBraceCount++;
+ if (lookingForCaseBrace) // if 1st after case statement
+ {
+ sw.unindentCase = true; // unindenting this case
+ sw.unindentDepth++;
+ lookingForCaseBrace = false; // not looking now
+ }
+ return i;
+ }
+ lookingForCaseBrace = false; // no opening brace, don't indent
+
+ if (line[i] == '}')
+ {
+ sw.switchBraceCount--;
+ assert(sw.switchBraceCount <= braceCount);
+ if (sw.switchBraceCount == 0) // if end of switch statement
+ {
+ int lineUnindent = sw.unindentDepth;
+ if (line.find_first_not_of(" \t") == i
+ && !switchStack.empty())
+ lineUnindent = switchStack[switchStack.size() - 1].unindentDepth;
+ if (shouldUnindentLine)
+ {
+ if (lineUnindent > 0)
+ i -= unindentLine(line, lineUnindent);
+ shouldUnindentLine = false;
+ }
+ switchDepth--;
+ sw = switchStack.back();
+ switchStack.pop_back();
+ }
+ return i;
+ }
+
+ if (isPotentialKeyword
+ && (findKeyword(line, i, ASResource::AS_CASE)
+ || findKeyword(line, i, ASResource::AS_DEFAULT)))
+ {
+ if (sw.unindentCase) // if unindented last case
+ {
+ sw.unindentCase = false; // stop unindenting previous case
+ sw.unindentDepth--;
+ }
+
+ i = findCaseColon(line, i);
+
+ i++;
+ for (; i < line.length(); i++) // bypass whitespace
+ {
+ if (!isWhiteSpace(line[i]))
+ break;
+ }
+ if (i < line.length())
+ {
+ if (line[i] == '{')
+ {
+ braceCount++;
+ sw.switchBraceCount++;
+ if (!isOneLineBlockReached(line, i))
+ unindentNextLine = true;
+ return i;
+ }
+ }
+ lookingForCaseBrace = true;
+ i--; // need to process this char
+ return i;
+ }
+ if (isPotentialKeyword)
+ {
+ string name = getCurrentWord(line, i); // bypass the entire name
+ i += name.length() - 1;
+ }
+ return i;
+}
+
+/**
+ * unindent a line by a given number of tabsets
+ * by erasing the leading whitespace from the line argument.
+ *
+ * @param line a reference to the line to unindent.
+ * @param unindent the number of tabsets to erase.
+ * @return the number of characters erased.
+ */
+int ASEnhancer::unindentLine(string& line, int unindent) const
+{
+ size_t whitespace = line.find_first_not_of(" \t");
+
+ if (whitespace == string::npos) // if line is blank
+ whitespace = line.length(); // must remove padding, if any
+
+ if (whitespace == 0)
+ return 0;
+
+ size_t charsToErase = 0;
+
+ if (forceTab && indentLength != tabLength)
+ {
+ // replace tab indents with spaces
+ convertForceTabIndentToSpaces(line);
+ // remove the space indents
+ size_t spaceIndentLength = line.find_first_not_of(" \t");
+ charsToErase = unindent * indentLength;
+ if (charsToErase <= spaceIndentLength)
+ line.erase(0, charsToErase);
+ else
+ charsToErase = 0;
+ // replace leading spaces with tab indents
+ convertSpaceIndentToForceTab(line);
+ }
+ else if (useTabs)
+ {
+ charsToErase = unindent;
+ if (charsToErase <= whitespace)
+ line.erase(0, charsToErase);
+ else
+ charsToErase = 0;
+ }
+ else // spaces
+ {
+ charsToErase = unindent * indentLength;
+ if (charsToErase <= whitespace)
+ line.erase(0, charsToErase);
+ else
+ charsToErase = 0;
+ }
+
+ return charsToErase;
+}
+
+} // end namespace astyle
--- /dev/null
+// ASFormatter.cpp
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+
+//-----------------------------------------------------------------------------
+// headers
+//-----------------------------------------------------------------------------
+
+#include "astyle.h"
+
+#include <algorithm>
+#include <fstream>
+
+//-----------------------------------------------------------------------------
+// astyle namespace
+//-----------------------------------------------------------------------------
+
+namespace astyle {
+//
+//-----------------------------------------------------------------------------
+// ASFormatter class
+//-----------------------------------------------------------------------------
+
+/**
+ * Constructor of ASFormatter
+ */
+ASFormatter::ASFormatter()
+{
+ sourceIterator = nullptr;
+ enhancer = new ASEnhancer;
+ preBraceHeaderStack = nullptr;
+ braceTypeStack = nullptr;
+ parenStack = nullptr;
+ structStack = nullptr;
+ questionMarkStack = nullptr;
+ lineCommentNoIndent = false;
+ formattingStyle = STYLE_NONE;
+ braceFormatMode = NONE_MODE;
+ pointerAlignment = PTR_ALIGN_NONE;
+ referenceAlignment = REF_SAME_AS_PTR;
+ objCColonPadMode = COLON_PAD_NO_CHANGE;
+ lineEnd = LINEEND_DEFAULT;
+ maxCodeLength = string::npos;
+ shouldPadCommas = false;
+ shouldPadOperators = false;
+ shouldPadParensOutside = false;
+ shouldPadFirstParen = false;
+ shouldPadParensInside = false;
+ shouldPadHeader = false;
+ shouldStripCommentPrefix = false;
+ shouldUnPadParens = false;
+ attachClosingBraceMode = false;
+ shouldBreakOneLineBlocks = true;
+ shouldBreakOneLineHeaders = false;
+ shouldBreakOneLineStatements = true;
+ shouldConvertTabs = false;
+ shouldIndentCol1Comments = false;
+ shouldIndentPreprocBlock = false;
+ shouldCloseTemplates = false;
+ shouldAttachExternC = false;
+ shouldAttachNamespace = false;
+ shouldAttachClass = false;
+ shouldAttachClosingWhile = false;
+ shouldAttachInline = false;
+ shouldBreakBlocks = false;
+ shouldBreakClosingHeaderBlocks = false;
+ shouldBreakClosingHeaderBraces = false;
+ shouldDeleteEmptyLines = false;
+ shouldBreakElseIfs = false;
+ shouldBreakLineAfterLogical = false;
+ shouldAddBraces = false;
+ shouldAddOneLineBraces = false;
+ shouldRemoveBraces = false;
+ shouldPadMethodColon = false;
+ shouldPadMethodPrefix = false;
+ shouldUnPadMethodPrefix = false;
+ shouldPadReturnType = false;
+ shouldUnPadReturnType = false;
+ shouldPadParamType = false;
+ shouldUnPadParamType = false;
+
+ // initialize ASFormatter member vectors
+ formatterFileType = 9; // reset to an invalid type
+ headers = new vector<const string*>;
+ nonParenHeaders = new vector<const string*>;
+ preDefinitionHeaders = new vector<const string*>;
+ preCommandHeaders = new vector<const string*>;
+ operators = new vector<const string*>;
+ assignmentOperators = new vector<const string*>;
+ castOperators = new vector<const string*>;
+
+ // initialize ASEnhancer member vectors
+ indentableMacros = new vector<const pair<const string, const string>* >;
+}
+
+/**
+ * Destructor of ASFormatter
+ */
+ASFormatter::~ASFormatter()
+{
+ // delete ASFormatter stack vectors
+ deleteContainer(preBraceHeaderStack);
+ deleteContainer(braceTypeStack);
+ deleteContainer(parenStack);
+ deleteContainer(structStack);
+ deleteContainer(questionMarkStack);
+
+ // delete ASFormatter member vectors
+ formatterFileType = 9; // reset to an invalid type
+ delete headers;
+ delete nonParenHeaders;
+ delete preDefinitionHeaders;
+ delete preCommandHeaders;
+ delete operators;
+ delete assignmentOperators;
+ delete castOperators;
+
+ // delete ASEnhancer member vectors
+ delete indentableMacros;
+
+ // must be done when the ASFormatter object is deleted (not ASBeautifier)
+ // delete ASBeautifier member vectors
+ ASBeautifier::deleteBeautifierVectors();
+
+ delete enhancer;
+}
+
+/**
+ * initialize the ASFormatter.
+ *
+ * init() should be called every time a ASFormatter object is to start
+ * formatting a NEW source file.
+ * init() receives a pointer to a ASSourceIterator object that will be
+ * used to iterate through the source code.
+ *
+ * @param si a pointer to the ASSourceIterator or ASStreamIterator object.
+ */
+void ASFormatter::init(ASSourceIterator* si)
+{
+ buildLanguageVectors();
+ fixOptionVariableConflicts();
+ ASBeautifier::init(si);
+ sourceIterator = si;
+
+ enhancer->init(getFileType(),
+ getIndentLength(),
+ getTabLength(),
+ getIndentString() == "\t",
+ getForceTabIndentation(),
+ getNamespaceIndent(),
+ getCaseIndent(),
+ shouldIndentPreprocBlock,
+ getPreprocDefineIndent(),
+ getEmptyLineFill(),
+ indentableMacros);
+
+ initContainer(preBraceHeaderStack, new vector<const string*>);
+ initContainer(parenStack, new vector<int>);
+ initContainer(structStack, new vector<bool>);
+ initContainer(questionMarkStack, new vector<bool>);
+ parenStack->emplace_back(0); // parenStack must contain this default entry
+ initContainer(braceTypeStack, new vector<BraceType>);
+ braceTypeStack->emplace_back(NULL_TYPE); // braceTypeStack must contain this default entry
+ clearFormattedLineSplitPoints();
+
+ currentHeader = nullptr;
+ currentLine = "";
+ readyFormattedLine = "";
+ formattedLine = "";
+ verbatimDelimiter = "";
+ currentChar = ' ';
+ previousChar = ' ';
+ previousCommandChar = ' ';
+ previousNonWSChar = ' ';
+ quoteChar = '"';
+ preprocBlockEnd = 0;
+ charNum = 0;
+ checksumIn = 0;
+ checksumOut = 0;
+ currentLineFirstBraceNum = string::npos;
+ formattedLineCommentNum = 0;
+ leadingSpaces = 0;
+ previousReadyFormattedLineLength = string::npos;
+ preprocBraceTypeStackSize = 0;
+ spacePadNum = 0;
+ nextLineSpacePadNum = 0;
+ objCColonAlign = 0;
+ templateDepth = 0;
+ squareBracketCount = 0;
+ runInIndentChars = 0;
+ tabIncrementIn = 0;
+ previousBraceType = NULL_TYPE;
+
+ isVirgin = true;
+ isInVirginLine = true;
+ isInLineComment = false;
+ isInComment = false;
+ isInCommentStartLine = false;
+ noTrimCommentContinuation = false;
+ isInPreprocessor = false;
+ isInPreprocessorBeautify = false;
+ doesLineStartComment = false;
+ lineEndsInCommentOnly = false;
+ lineIsCommentOnly = false;
+ lineIsLineCommentOnly = false;
+ lineIsEmpty = false;
+ isImmediatelyPostCommentOnly = false;
+ isImmediatelyPostEmptyLine = false;
+ isInClassInitializer = false;
+ isInQuote = false;
+ isInVerbatimQuote = false;
+ haveLineContinuationChar = false;
+ isInQuoteContinuation = false;
+ isHeaderInMultiStatementLine = false;
+ isSpecialChar = false;
+ isNonParenHeader = false;
+ foundNamespaceHeader = false;
+ foundClassHeader = false;
+ foundStructHeader = false;
+ foundInterfaceHeader = false;
+ foundPreDefinitionHeader = false;
+ foundPreCommandHeader = false;
+ foundPreCommandMacro = false;
+ foundTrailingReturnType = false;
+ foundCastOperator = false;
+ foundQuestionMark = false;
+ isInLineBreak = false;
+ endOfAsmReached = false;
+ endOfCodeReached = false;
+ isFormattingModeOff = false;
+ isInEnum = false;
+ isInExecSQL = false;
+ isInAsm = false;
+ isInAsmOneLine = false;
+ isInAsmBlock = false;
+ isLineReady = false;
+ elseHeaderFollowsComments = false;
+ caseHeaderFollowsComments = false;
+ isPreviousBraceBlockRelated = false;
+ isInPotentialCalculation = false;
+ needHeaderOpeningBrace = false;
+ shouldBreakLineAtNextChar = false;
+ shouldKeepLineUnbroken = false;
+ shouldReparseCurrentChar = false;
+ passedSemicolon = false;
+ passedColon = false;
+ isImmediatelyPostNonInStmt = false;
+ isCharImmediatelyPostNonInStmt = false;
+ isInTemplate = false;
+ isImmediatelyPostComment = false;
+ isImmediatelyPostLineComment = false;
+ isImmediatelyPostEmptyBlock = false;
+ isImmediatelyPostObjCMethodPrefix = false;
+ isImmediatelyPostPreprocessor = false;
+ isImmediatelyPostReturn = false;
+ isImmediatelyPostThrow = false;
+ isImmediatelyPostNewDelete = false;
+ isImmediatelyPostOperator = false;
+ isImmediatelyPostTemplate = false;
+ isImmediatelyPostPointerOrReference = false;
+ isCharImmediatelyPostReturn = false;
+ isCharImmediatelyPostThrow = false;
+ isCharImmediatelyPostNewDelete = false;
+ isCharImmediatelyPostOperator = false;
+ isCharImmediatelyPostComment = false;
+ isPreviousCharPostComment = false;
+ isCharImmediatelyPostLineComment = false;
+ isCharImmediatelyPostOpenBlock = false;
+ isCharImmediatelyPostCloseBlock = false;
+ isCharImmediatelyPostTemplate = false;
+ isCharImmediatelyPostPointerOrReference = false;
+ isInObjCInterface = false;
+ isInObjCMethodDefinition = false;
+ isInObjCReturnType = false;
+ isInObjCSelector = false;
+ breakCurrentOneLineBlock = false;
+ shouldRemoveNextClosingBrace = false;
+ isInBraceRunIn = false;
+ currentLineBeginsWithBrace = false;
+ isPrependPostBlockEmptyLineRequested = false;
+ isAppendPostBlockEmptyLineRequested = false;
+ isIndentableProprocessor = false;
+ isIndentableProprocessorBlock = false;
+ prependEmptyLine = false;
+ appendOpeningBrace = false;
+ foundClosingHeader = false;
+ isImmediatelyPostHeader = false;
+ isInHeader = false;
+ isInCase = false;
+ isFirstPreprocConditional = false;
+ processedFirstConditional = false;
+ isJavaStaticConstructor = false;
+}
+
+/**
+ * build vectors for each programing language
+ * depending on the file extension.
+ */
+void ASFormatter::buildLanguageVectors()
+{
+ if (getFileType() == formatterFileType) // don't build unless necessary
+ return;
+
+ formatterFileType = getFileType();
+
+ headers->clear();
+ nonParenHeaders->clear();
+ preDefinitionHeaders->clear();
+ preCommandHeaders->clear();
+ operators->clear();
+ assignmentOperators->clear();
+ castOperators->clear();
+ indentableMacros->clear(); // ASEnhancer
+
+ ASResource::buildHeaders(headers, getFileType());
+ ASResource::buildNonParenHeaders(nonParenHeaders, getFileType());
+ ASResource::buildPreDefinitionHeaders(preDefinitionHeaders, getFileType());
+ ASResource::buildPreCommandHeaders(preCommandHeaders, getFileType());
+ ASResource::buildOperators(operators, getFileType());
+ ASResource::buildAssignmentOperators(assignmentOperators);
+ ASResource::buildCastOperators(castOperators);
+ ASResource::buildIndentableMacros(indentableMacros); //ASEnhancer
+}
+
+/**
+ * set the variables for each predefined style.
+ * this will override any previous settings.
+ */
+void ASFormatter::fixOptionVariableConflicts()
+{
+ if (formattingStyle == STYLE_ALLMAN)
+ {
+ setBraceFormatMode(BREAK_MODE);
+ }
+ else if (formattingStyle == STYLE_JAVA)
+ {
+ setBraceFormatMode(ATTACH_MODE);
+ }
+ else if (formattingStyle == STYLE_KR)
+ {
+ setBraceFormatMode(LINUX_MODE);
+ }
+ else if (formattingStyle == STYLE_STROUSTRUP)
+ {
+ setBraceFormatMode(LINUX_MODE);
+ setBreakClosingHeaderBracesMode(true);
+ }
+ else if (formattingStyle == STYLE_WHITESMITH)
+ {
+ setBraceFormatMode(BREAK_MODE);
+ setBraceIndent(true);
+ setClassIndent(true); // avoid hanging indent with access modifiers
+ setSwitchIndent(true); // avoid hanging indent with case statements
+ }
+ else if (formattingStyle == STYLE_VTK)
+ {
+ // the unindented class brace does NOT cause a hanging indent like Whitesmith
+ setBraceFormatMode(BREAK_MODE);
+ setBraceIndentVtk(true); // sets both braceIndent and braceIndentVtk
+ setSwitchIndent(true); // avoid hanging indent with case statements
+ }
+ else if (formattingStyle == STYLE_BANNER)
+ {
+ // attached braces can have hanging indents with the closing brace
+ setBraceFormatMode(ATTACH_MODE);
+ setBraceIndent(true);
+ setClassIndent(true); // avoid hanging indent with access modifiers
+ setSwitchIndent(true); // avoid hanging indent with case statements
+ }
+ else if (formattingStyle == STYLE_GNU)
+ {
+ setBraceFormatMode(BREAK_MODE);
+ setBlockIndent(true);
+ }
+ else if (formattingStyle == STYLE_LINUX)
+ {
+ setBraceFormatMode(LINUX_MODE);
+ // always for Linux style
+ setMinConditionalIndentOption(MINCOND_ONEHALF);
+ }
+ else if (formattingStyle == STYLE_HORSTMANN)
+ {
+ setBraceFormatMode(RUN_IN_MODE);
+ setSwitchIndent(true);
+ }
+ else if (formattingStyle == STYLE_1TBS)
+ {
+ setBraceFormatMode(LINUX_MODE);
+ setAddBracesMode(true);
+ setRemoveBracesMode(false);
+ }
+ else if (formattingStyle == STYLE_GOOGLE)
+ {
+ setBraceFormatMode(ATTACH_MODE);
+ setModifierIndent(true);
+ setClassIndent(false);
+ }
+ else if (formattingStyle == STYLE_MOZILLA)
+ {
+ setBraceFormatMode(LINUX_MODE);
+ }
+ else if (formattingStyle == STYLE_PICO)
+ {
+ setBraceFormatMode(RUN_IN_MODE);
+ setAttachClosingBraceMode(true);
+ setSwitchIndent(true);
+ setBreakOneLineBlocksMode(false);
+ setBreakOneLineStatementsMode(false);
+ // add-braces won't work for pico, but it could be fixed if necessary
+ // both options should be set to true
+ if (shouldAddBraces)
+ shouldAddOneLineBraces = true;
+ }
+ else if (formattingStyle == STYLE_LISP)
+ {
+ setBraceFormatMode(ATTACH_MODE);
+ setAttachClosingBraceMode(true);
+ setBreakOneLineStatementsMode(false);
+ // add-one-line-braces won't work for lisp
+ // only shouldAddBraces should be set to true
+ if (shouldAddOneLineBraces)
+ {
+ shouldAddBraces = true;
+ shouldAddOneLineBraces = false;
+ }
+ }
+ setMinConditionalIndentLength();
+ // if not set by indent=force-tab-x set equal to indentLength
+ if (getTabLength() == 0)
+ setDefaultTabLength();
+ // add-one-line-braces implies keep-one-line-blocks
+ if (shouldAddOneLineBraces)
+ setBreakOneLineBlocksMode(false);
+ // don't allow add-braces and remove-braces
+ if (shouldAddBraces || shouldAddOneLineBraces)
+ setRemoveBracesMode(false);
+ // don't allow indent-classes and indent-modifiers
+ if (getClassIndent())
+ setModifierIndent(false);
+}
+
+/**
+ * get the next formatted line.
+ *
+ * @return formatted line.
+ */
+string ASFormatter::nextLine()
+{
+ const string* newHeader = nullptr;
+ isInVirginLine = isVirgin;
+ isCharImmediatelyPostComment = false;
+ isPreviousCharPostComment = false;
+ isCharImmediatelyPostLineComment = false;
+ isCharImmediatelyPostOpenBlock = false;
+ isCharImmediatelyPostCloseBlock = false;
+ isCharImmediatelyPostTemplate = false;
+
+ while (!isLineReady)
+ {
+ if (shouldReparseCurrentChar)
+ shouldReparseCurrentChar = false;
+ else if (!getNextChar())
+ {
+ breakLine();
+ continue;
+ }
+ else // stuff to do when reading a new character...
+ {
+ // make sure that a virgin '{' at the beginning of the file will be treated as a block...
+ if (isInVirginLine && currentChar == '{'
+ && currentLineBeginsWithBrace
+ && previousCommandChar == ' ')
+ previousCommandChar = '{';
+ if (isInClassInitializer
+ && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
+ isInClassInitializer = false;
+ if (isInBraceRunIn)
+ isInLineBreak = false;
+ if (!isWhiteSpace(currentChar))
+ isInBraceRunIn = false;
+ isPreviousCharPostComment = isCharImmediatelyPostComment;
+ isCharImmediatelyPostComment = false;
+ isCharImmediatelyPostTemplate = false;
+ isCharImmediatelyPostReturn = false;
+ isCharImmediatelyPostThrow = false;
+ isCharImmediatelyPostNewDelete = false;
+ isCharImmediatelyPostOperator = false;
+ isCharImmediatelyPostPointerOrReference = false;
+ isCharImmediatelyPostOpenBlock = false;
+ isCharImmediatelyPostCloseBlock = false;
+ }
+
+ if ((lineIsLineCommentOnly || lineIsCommentOnly)
+ && currentLine.find("*INDENT-ON*", charNum) != string::npos
+ && isFormattingModeOff)
+ {
+ isFormattingModeOff = false;
+ breakLine();
+ formattedLine = currentLine;
+ charNum = (int) currentLine.length() - 1;
+ continue;
+ }
+ if (isFormattingModeOff)
+ {
+ breakLine();
+ formattedLine = currentLine;
+ charNum = (int) currentLine.length() - 1;
+ continue;
+ }
+ if ((lineIsLineCommentOnly || lineIsCommentOnly)
+ && currentLine.find("*INDENT-OFF*", charNum) != string::npos)
+ {
+ isFormattingModeOff = true;
+ if (isInLineBreak) // is true if not the first line
+ breakLine();
+ formattedLine = currentLine;
+ charNum = (int)currentLine.length() - 1;
+ continue;
+ }
+
+ if (shouldBreakLineAtNextChar)
+ {
+ if (isWhiteSpace(currentChar) && !lineIsEmpty)
+ continue;
+ isInLineBreak = true;
+ shouldBreakLineAtNextChar = false;
+ }
+
+ if (isInExecSQL && !passedSemicolon)
+ {
+ if (currentChar == ';')
+ passedSemicolon = true;
+ appendCurrentChar();
+ continue;
+ }
+
+ if (isInLineComment)
+ {
+ formatLineCommentBody();
+ continue;
+ }
+ else if (isInComment)
+ {
+ formatCommentBody();
+ continue;
+ }
+
+ else if (isInQuote)
+ {
+ formatQuoteBody();
+ continue;
+ }
+
+ // not in quote or comment or line comment
+
+ if (isSequenceReached("//"))
+ {
+ formatLineCommentOpener();
+ testForTimeToSplitFormattedLine();
+ continue;
+ }
+ else if (isSequenceReached("/*"))
+ {
+ formatCommentOpener();
+ testForTimeToSplitFormattedLine();
+ continue;
+ }
+ else if (currentChar == '"'
+ || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)))
+ {
+ formatQuoteOpener();
+ testForTimeToSplitFormattedLine();
+ continue;
+ }
+ // treat these preprocessor statements as a line comment
+ else if (currentChar == '#'
+ && currentLine.find_first_not_of(" \t") == (size_t) charNum)
+ {
+ string preproc = trim(currentLine.c_str() + charNum + 1);
+ if (preproc.length() > 0
+ && isCharPotentialHeader(preproc, 0)
+ && (findKeyword(preproc, 0, "region")
+ || findKeyword(preproc, 0, "endregion")
+ || findKeyword(preproc, 0, "error")
+ || findKeyword(preproc, 0, "warning")
+ || findKeyword(preproc, 0, "line")))
+ {
+ currentLine = rtrim(currentLine); // trim the end only
+ // check for run-in
+ if (formattedLine.length() > 0 && formattedLine[0] == '{')
+ {
+ isInLineBreak = true;
+ isInBraceRunIn = false;
+ }
+ if (previousCommandChar == '}')
+ currentHeader = nullptr;
+ isInLineComment = true;
+ appendCurrentChar();
+ continue;
+ }
+ }
+
+ if (isInPreprocessor)
+ {
+ appendCurrentChar();
+ continue;
+ }
+
+ if (isInTemplate && shouldCloseTemplates)
+ {
+ if (previousNonWSChar == '>' && isWhiteSpace(currentChar) && peekNextChar() == '>')
+ continue;
+ }
+
+ if (shouldRemoveNextClosingBrace && currentChar == '}')
+ {
+ currentLine[charNum] = currentChar = ' ';
+ shouldRemoveNextClosingBrace = false;
+ assert(adjustChecksumIn(-'}'));
+ if (isEmptyLine(currentLine))
+ continue;
+ }
+
+ // handle white space - needed to simplify the rest.
+ if (isWhiteSpace(currentChar))
+ {
+ appendCurrentChar();
+ continue;
+ }
+
+ /* not in MIDDLE of quote or comment or SQL or white-space of any type ... */
+
+ // check if in preprocessor
+ // ** isInPreprocessor will be automatically reset at the beginning
+ // of a new line in getnextChar()
+ if (currentChar == '#')
+ {
+ isInPreprocessor = true;
+ // check for run-in
+ if (formattedLine.length() > 0 && formattedLine[0] == '{')
+ {
+ isInLineBreak = true;
+ isInBraceRunIn = false;
+ }
+ processPreprocessor();
+ // if top level it is potentially indentable
+ if (shouldIndentPreprocBlock
+ && (isBraceType(braceTypeStack->back(), NULL_TYPE)
+ || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
+ && !foundClassHeader
+ && !isInClassInitializer
+ && sourceIterator->tellg() > preprocBlockEnd)
+ {
+ // indent the #if preprocessor blocks
+ string preproc = ASBeautifier::extractPreprocessorStatement(currentLine);
+ if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
+ {
+ if (isImmediatelyPostPreprocessor)
+ breakLine();
+ isIndentableProprocessorBlock = isIndentablePreprocessorBlock(currentLine, charNum);
+ isIndentableProprocessor = isIndentableProprocessorBlock;
+ }
+ }
+ if (isIndentableProprocessorBlock
+ && charNum < (int) currentLine.length() - 1
+ && isWhiteSpace(currentLine[charNum + 1]))
+ {
+ size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (nextText != string::npos)
+ currentLine.erase(charNum + 1, nextText - charNum - 1);
+ }
+ if (isIndentableProprocessorBlock
+ && sourceIterator->tellg() >= preprocBlockEnd)
+ isIndentableProprocessorBlock = false;
+ // need to fall thru here to reset the variables
+ }
+
+ /* not in preprocessor ... */
+
+ if (isImmediatelyPostComment)
+ {
+ caseHeaderFollowsComments = false;
+ isImmediatelyPostComment = false;
+ isCharImmediatelyPostComment = true;
+ }
+
+ if (isImmediatelyPostLineComment)
+ {
+ caseHeaderFollowsComments = false;
+ isImmediatelyPostLineComment = false;
+ isCharImmediatelyPostLineComment = true;
+ }
+
+ if (isImmediatelyPostReturn)
+ {
+ isImmediatelyPostReturn = false;
+ isCharImmediatelyPostReturn = true;
+ }
+
+ if (isImmediatelyPostThrow)
+ {
+ isImmediatelyPostThrow = false;
+ isCharImmediatelyPostThrow = true;
+ }
+
+ if (isImmediatelyPostNewDelete)
+ {
+ isImmediatelyPostNewDelete = false;
+ isCharImmediatelyPostNewDelete = true;
+ }
+
+ if (isImmediatelyPostOperator)
+ {
+ isImmediatelyPostOperator = false;
+ isCharImmediatelyPostOperator = true;
+ }
+ if (isImmediatelyPostTemplate)
+ {
+ isImmediatelyPostTemplate = false;
+ isCharImmediatelyPostTemplate = true;
+ }
+ if (isImmediatelyPostPointerOrReference)
+ {
+ isImmediatelyPostPointerOrReference = false;
+ isCharImmediatelyPostPointerOrReference = true;
+ }
+
+ // reset isImmediatelyPostHeader information
+ if (isImmediatelyPostHeader)
+ {
+ // should braces be added
+ if (currentChar != '{'
+ && shouldAddBraces
+ && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine)
+ && isOkToBreakBlock(braceTypeStack->back()))
+ {
+ bool bracesAdded = addBracesToStatement();
+ if (bracesAdded && !shouldAddOneLineBraces)
+ {
+ size_t firstText = currentLine.find_first_not_of(" \t");
+ assert(firstText != string::npos);
+ if ((int) firstText == charNum || shouldBreakOneLineHeaders)
+ breakCurrentOneLineBlock = true;
+ }
+ }
+ // should braces be removed
+ else if (currentChar == '{' && shouldRemoveBraces)
+ {
+ bool bracesRemoved = removeBracesFromStatement();
+ if (bracesRemoved)
+ {
+ shouldRemoveNextClosingBrace = true;
+ if (isBeforeAnyLineEndComment(charNum))
+ spacePadNum--;
+ else if (shouldBreakOneLineBlocks
+ || (currentLineBeginsWithBrace
+ && currentLine.find_first_not_of(" \t") != string::npos))
+ shouldBreakLineAtNextChar = true;
+ continue;
+ }
+ }
+
+ // break 'else-if' if shouldBreakElseIfs is requested
+ if (shouldBreakElseIfs
+ && currentHeader == &AS_ELSE
+ && isOkToBreakBlock(braceTypeStack->back())
+ && !isBeforeAnyComment()
+ && (shouldBreakOneLineStatements || !isHeaderInMultiStatementLine))
+ {
+ string nextText = peekNextText(currentLine.substr(charNum));
+ if (nextText.length() > 0
+ && isCharPotentialHeader(nextText, 0)
+ && ASBase::findHeader(nextText, 0, headers) == &AS_IF)
+ {
+ isInLineBreak = true;
+ }
+ }
+
+ // break a header (e.g. if, while, else) from the following statement
+ if (shouldBreakOneLineHeaders
+ && peekNextChar() != ' '
+ && (shouldBreakOneLineStatements
+ || (!isHeaderInMultiStatementLine
+ && !isMultiStatementLine()))
+ && isOkToBreakBlock(braceTypeStack->back())
+ && !isBeforeAnyComment())
+ {
+ if (currentChar == '{')
+ {
+ if (!currentLineBeginsWithBrace)
+ {
+ if (isOneLineBlockReached(currentLine, charNum) == 3)
+ isInLineBreak = false;
+ else
+ breakCurrentOneLineBlock = true;
+ }
+ }
+ else if (currentHeader == &AS_ELSE)
+ {
+ string nextText = peekNextText(currentLine.substr(charNum), true);
+ if (nextText.length() > 0
+ && ((isCharPotentialHeader(nextText, 0)
+ && ASBase::findHeader(nextText, 0, headers) != &AS_IF)
+ || nextText[0] == '{'))
+ isInLineBreak = true;
+ }
+ else
+ {
+ isInLineBreak = true;
+ }
+ }
+
+ isImmediatelyPostHeader = false;
+ }
+
+ if (passedSemicolon) // need to break the formattedLine
+ {
+ passedSemicolon = false;
+ if (parenStack->back() == 0 && !isCharImmediatelyPostComment && currentChar != ';') // allow ;;
+ {
+ // does a one-line block have ending comments?
+ if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
+ {
+ size_t blockEnd = currentLine.rfind(AS_CLOSE_BRACE);
+ assert(blockEnd != string::npos);
+ // move ending comments to this formattedLine
+ if (isBeforeAnyLineEndComment(blockEnd))
+ {
+ size_t commentStart = currentLine.find_first_not_of(" \t", blockEnd + 1);
+ assert(commentStart != string::npos);
+ assert((currentLine.compare(commentStart, 2, "//") == 0)
+ || (currentLine.compare(commentStart, 2, "/*") == 0));
+ formattedLine.append(getIndentLength() - 1, ' ');
+ // append comment
+ int charNumSave = charNum;
+ charNum = commentStart;
+ while (charNum < (int) currentLine.length())
+ {
+ currentChar = currentLine[charNum];
+ if (currentChar == '\t' && shouldConvertTabs)
+ convertTabToSpaces();
+ formattedLine.append(1, currentChar);
+ ++charNum;
+ }
+ size_t commentLength = currentLine.length() - commentStart;
+ currentLine.erase(commentStart, commentLength);
+ charNum = charNumSave;
+ currentChar = currentLine[charNum];
+ testForTimeToSplitFormattedLine();
+ }
+ }
+ isInExecSQL = false;
+ shouldReparseCurrentChar = true;
+ if (formattedLine.find_first_not_of(" \t") != string::npos)
+ isInLineBreak = true;
+ if (needHeaderOpeningBrace)
+ {
+ isCharImmediatelyPostCloseBlock = true;
+ needHeaderOpeningBrace = false;
+ }
+ continue;
+ }
+ }
+
+ if (passedColon)
+ {
+ passedColon = false;
+ if (parenStack->back() == 0
+ && !isBeforeAnyComment()
+ && (formattedLine.find_first_not_of(" \t") != string::npos))
+ {
+ shouldReparseCurrentChar = true;
+ isInLineBreak = true;
+ continue;
+ }
+ }
+
+ // Check if in template declaration, e.g. foo<bar> or foo<bar,fig>
+ if (!isInTemplate && currentChar == '<')
+ {
+ checkIfTemplateOpener();
+ }
+
+ // handle parens
+ if (currentChar == '(' || currentChar == '[' || (isInTemplate && currentChar == '<'))
+ {
+ questionMarkStack->push_back(foundQuestionMark);
+ foundQuestionMark = false;
+ parenStack->back()++;
+ if (currentChar == '[')
+ {
+ ++squareBracketCount;
+ if (getAlignMethodColon() && squareBracketCount == 1 && isCStyle())
+ objCColonAlign = findObjCColonAlignment();
+ }
+ }
+ else if (currentChar == ')' || currentChar == ']' || (isInTemplate && currentChar == '>'))
+ {
+ foundPreCommandHeader = false;
+ parenStack->back()--;
+ // this can happen in preprocessor directives
+ if (parenStack->back() < 0)
+ parenStack->back() = 0;
+ if (!questionMarkStack->empty())
+ {
+ foundQuestionMark = questionMarkStack->back();
+ questionMarkStack->pop_back();
+ }
+ if (isInTemplate && currentChar == '>')
+ {
+ templateDepth--;
+ if (templateDepth == 0)
+ {
+ isInTemplate = false;
+ isImmediatelyPostTemplate = true;
+ }
+ }
+
+ // check if this parenthesis closes a header, e.g. if (...), while (...)
+ if (isInHeader && parenStack->back() == 0)
+ {
+ isInHeader = false;
+ isImmediatelyPostHeader = true;
+ foundQuestionMark = false;
+ }
+ if (currentChar == ']')
+ {
+ --squareBracketCount;
+ if (squareBracketCount <= 0)
+ {
+ squareBracketCount = 0;
+ objCColonAlign = 0;
+ }
+ }
+ if (currentChar == ')')
+ {
+ foundCastOperator = false;
+ if (parenStack->back() == 0)
+ endOfAsmReached = true;
+ }
+ }
+
+ // handle braces
+ if (currentChar == '{' || currentChar == '}')
+ {
+ // if appendOpeningBrace this was already done for the original brace
+ if (currentChar == '{' && !appendOpeningBrace)
+ {
+ BraceType newBraceType = getBraceType();
+ breakCurrentOneLineBlock = false;
+ foundNamespaceHeader = false;
+ foundClassHeader = false;
+ foundStructHeader = false;
+ foundInterfaceHeader = false;
+ foundPreDefinitionHeader = false;
+ foundPreCommandHeader = false;
+ foundPreCommandMacro = false;
+ foundTrailingReturnType = false;
+ isInPotentialCalculation = false;
+ isInObjCMethodDefinition = false;
+ isInObjCInterface = false;
+ isInEnum = false;
+ isJavaStaticConstructor = false;
+ isCharImmediatelyPostNonInStmt = false;
+ needHeaderOpeningBrace = false;
+ shouldKeepLineUnbroken = false;
+ objCColonAlign = 0;
+
+ isPreviousBraceBlockRelated = !isBraceType(newBraceType, ARRAY_TYPE);
+ braceTypeStack->emplace_back(newBraceType);
+ preBraceHeaderStack->emplace_back(currentHeader);
+ currentHeader = nullptr;
+ structStack->push_back(isInIndentableStruct);
+ if (isBraceType(newBraceType, STRUCT_TYPE) && isCStyle())
+ isInIndentableStruct = isStructAccessModified(currentLine, charNum);
+ else
+ isInIndentableStruct = false;
+ }
+
+ // this must be done before the braceTypeStack is popped
+ BraceType braceType = braceTypeStack->back();
+ bool isOpeningArrayBrace = (isBraceType(braceType, ARRAY_TYPE)
+ && braceTypeStack->size() >= 2
+ && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2], ARRAY_TYPE)
+ );
+
+ if (currentChar == '}')
+ {
+ // if a request has been made to append a post block empty line,
+ // but the block exists immediately before a closing brace,
+ // then there is no need for the post block empty line.
+ isAppendPostBlockEmptyLineRequested = false;
+ if (isInAsm)
+ endOfAsmReached = true;
+ isInAsmOneLine = isInQuote = false;
+ shouldKeepLineUnbroken = false;
+ squareBracketCount = 0;
+
+ if (braceTypeStack->size() > 1)
+ {
+ previousBraceType = braceTypeStack->back();
+ braceTypeStack->pop_back();
+ isPreviousBraceBlockRelated = !isBraceType(braceType, ARRAY_TYPE);
+ }
+ else
+ {
+ previousBraceType = NULL_TYPE;
+ isPreviousBraceBlockRelated = false;
+ }
+
+ if (!preBraceHeaderStack->empty())
+ {
+ currentHeader = preBraceHeaderStack->back();
+ preBraceHeaderStack->pop_back();
+ }
+ else
+ currentHeader = nullptr;
+
+ if (!structStack->empty())
+ {
+ isInIndentableStruct = structStack->back();
+ structStack->pop_back();
+ }
+ else
+ isInIndentableStruct = false;
+
+ if (isNonInStatementArray
+ && (!isBraceType(braceTypeStack->back(), ARRAY_TYPE) // check previous brace
+ || peekNextChar() == ';')) // check for "};" added V2.01
+ isImmediatelyPostNonInStmt = true;
+
+ if (!shouldBreakOneLineStatements
+ && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE)
+ {
+ // handle special case of "else" at the end of line
+ size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')
+ shouldBreakLineAtNextChar = true;
+ }
+ }
+
+ // format braces
+ appendOpeningBrace = false;
+ if (isBraceType(braceType, ARRAY_TYPE))
+ {
+ formatArrayBraces(braceType, isOpeningArrayBrace);
+ }
+ else
+ {
+ if (currentChar == '{')
+ formatOpeningBrace(braceType);
+ else
+ formatClosingBrace(braceType);
+ }
+ continue;
+ }
+
+ if ((((previousCommandChar == '{' && isPreviousBraceBlockRelated)
+ || ((previousCommandChar == '}'
+ && !isImmediatelyPostEmptyBlock
+ && isPreviousBraceBlockRelated
+ && !isPreviousCharPostComment // Fixes wrongly appended newlines after '}' immediately after comments
+ && peekNextChar() != ' '
+ && !isBraceType(previousBraceType, DEFINITION_TYPE))
+ && !isBraceType(braceTypeStack->back(), DEFINITION_TYPE)))
+ && isOkToBreakBlock(braceTypeStack->back()))
+ // check for array
+ || (previousCommandChar == '{' // added 9/30/2010
+ && isBraceType(braceTypeStack->back(), ARRAY_TYPE)
+ && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
+ && isNonInStatementArray)
+ // check for pico one line braces
+ || (formattingStyle == STYLE_PICO
+ && (previousCommandChar == '{' && isPreviousBraceBlockRelated)
+ && isBraceType(braceTypeStack->back(), COMMAND_TYPE)
+ && isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
+ && braceFormatMode == RUN_IN_MODE)
+ )
+ {
+ isCharImmediatelyPostOpenBlock = (previousCommandChar == '{');
+ isCharImmediatelyPostCloseBlock = (previousCommandChar == '}');
+
+ if (isCharImmediatelyPostOpenBlock
+ && !isCharImmediatelyPostComment
+ && !isCharImmediatelyPostLineComment)
+ {
+ previousCommandChar = ' ';
+
+ if (braceFormatMode == NONE_MODE)
+ {
+ if (isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
+ && (isBraceType(braceTypeStack->back(), BREAK_BLOCK_TYPE)
+ || shouldBreakOneLineBlocks))
+ isInLineBreak = true;
+ else if (currentLineBeginsWithBrace)
+ formatRunIn();
+ else
+ breakLine();
+ }
+ else if (braceFormatMode == RUN_IN_MODE
+ && currentChar != '#')
+ formatRunIn();
+ else
+ isInLineBreak = true;
+ }
+ else if (isCharImmediatelyPostCloseBlock
+ && shouldBreakOneLineStatements
+ && !isCharImmediatelyPostComment
+ && ((isLegalNameChar(currentChar) && currentChar != '.')
+ || currentChar == '+'
+ || currentChar == '-'
+ || currentChar == '*'
+ || currentChar == '&'
+ || currentChar == '('))
+ {
+ previousCommandChar = ' ';
+ isInLineBreak = true;
+ }
+ }
+
+ // reset block handling flags
+ isImmediatelyPostEmptyBlock = false;
+
+ // look for headers
+ bool isPotentialHeader = isCharPotentialHeader(currentLine, charNum);
+
+ if (isPotentialHeader && !isInTemplate && squareBracketCount == 0)
+ {
+ isNonParenHeader = false;
+ foundClosingHeader = false;
+
+ newHeader = findHeader(headers);
+
+ // Qt headers may be variables in C++
+ if (isCStyle()
+ && (newHeader == &AS_FOREVER || newHeader == &AS_FOREACH))
+ {
+ if (currentLine.find_first_of("=;", charNum) != string::npos)
+ newHeader = nullptr;
+ }
+ if (isJavaStyle()
+ && (newHeader == &AS_SYNCHRONIZED))
+ {
+ // want synchronized statements not synchronized methods
+ if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE))
+ newHeader = nullptr;
+ }
+ else if (newHeader == &AS_USING
+ && ASBeautifier::peekNextChar(
+ currentLine, charNum + (*newHeader).length() - 1) != '(')
+ newHeader = nullptr;
+
+ if (newHeader != nullptr)
+ {
+ foundClosingHeader = isClosingHeader(newHeader);
+
+ if (!foundClosingHeader)
+ {
+ // these are closing headers
+ if ((newHeader == &AS_WHILE && currentHeader == &AS_DO)
+ || (newHeader == &_AS_FINALLY && currentHeader == &_AS_TRY)
+ || (newHeader == &_AS_EXCEPT && currentHeader == &_AS_TRY))
+ foundClosingHeader = true;
+ // don't append empty block for these related headers
+ else if (isSharpStyle()
+ && previousNonWSChar == '}'
+ && ((newHeader == &AS_SET && currentHeader == &AS_GET)
+ || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
+ && isOkToBreakBlock(braceTypeStack->back()))
+ isAppendPostBlockEmptyLineRequested = false;
+ }
+
+ // TODO: this can be removed in a future release
+ // version 3.0 - break erroneous attached header from previous versions
+ if (isSharpStyle()
+ && ((newHeader == &AS_SET && currentHeader == &AS_GET)
+ || (newHeader == &AS_REMOVE && currentHeader == &AS_ADD))
+ && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
+ && currentLine[currentLine.find_first_not_of(" \t")] == '}')
+ isInLineBreak = true;
+ // END TODO
+
+ const string* previousHeader = currentHeader;
+ currentHeader = newHeader;
+ needHeaderOpeningBrace = true;
+
+ // is the previous statement on the same line?
+ if ((previousNonWSChar == ';' || previousNonWSChar == ':')
+ && !isInLineBreak
+ && isOkToBreakBlock(braceTypeStack->back()))
+ {
+ // if breaking lines, break the line at the header
+ // except for multiple 'case' statements on a line
+ if (maxCodeLength != string::npos
+ && previousHeader != &AS_CASE)
+ isInLineBreak = true;
+ else
+ isHeaderInMultiStatementLine = true;
+ }
+
+ if (foundClosingHeader && previousNonWSChar == '}')
+ {
+ if (isOkToBreakBlock(braceTypeStack->back()))
+ isLineBreakBeforeClosingHeader();
+
+ // get the adjustment for a comment following the closing header
+ if (isInLineBreak)
+ nextLineSpacePadNum = getNextLineCommentAdjustment();
+ else
+ spacePadNum = getCurrentLineCommentAdjustment();
+ }
+
+ // check if the found header is non-paren header
+ isNonParenHeader = findHeader(nonParenHeaders) != nullptr;
+
+ if (isNonParenHeader
+ && (currentHeader == &AS_CATCH
+ || currentHeader == &AS_CASE))
+ {
+ int startChar = charNum + currentHeader->length() - 1;
+ if (ASBeautifier::peekNextChar(currentLine, startChar) == '(')
+ isNonParenHeader = false;
+ }
+
+ // join 'else if' statements
+ if (currentHeader == &AS_IF
+ && previousHeader == &AS_ELSE
+ && isInLineBreak
+ && !shouldBreakElseIfs
+ && !isCharImmediatelyPostLineComment
+ && !isImmediatelyPostPreprocessor)
+ {
+ // 'else' must be last thing on the line
+ size_t start = formattedLine.length() >= 6 ? formattedLine.length() - 6 : 0;
+ if (formattedLine.find(AS_ELSE, start) != string::npos)
+ {
+ appendSpacePad();
+ isInLineBreak = false;
+ }
+ }
+
+ appendSequence(*currentHeader);
+ goForward(currentHeader->length() - 1);
+ // if a paren-header is found add a space after it, if needed
+ // this checks currentLine, appendSpacePad() checks formattedLine
+ // in 'case' and C# 'catch' can be either a paren or non-paren header
+ if (shouldPadHeader
+ && !isNonParenHeader
+ && charNum < (int) currentLine.length() - 1 && !isWhiteSpace(currentLine[charNum + 1]))
+ appendSpacePad();
+
+ // Signal that a header has been reached
+ // *** But treat a closing while() (as in do...while)
+ // as if it were NOT a header since a closing while()
+ // should never have a block after it!
+ if (currentHeader != &AS_CASE && currentHeader != &AS_DEFAULT
+ && !(foundClosingHeader && currentHeader == &AS_WHILE))
+ {
+ isInHeader = true;
+
+ // in C# 'catch' and 'delegate' can be a paren or non-paren header
+ if (isNonParenHeader && !isSharpStyleWithParen(currentHeader))
+ {
+ isImmediatelyPostHeader = true;
+ isInHeader = false;
+ }
+ }
+
+ if (shouldBreakBlocks
+ && isOkToBreakBlock(braceTypeStack->back())
+ && !isHeaderInMultiStatementLine)
+ {
+ if (previousHeader == nullptr
+ && !foundClosingHeader
+ && !isCharImmediatelyPostOpenBlock
+ && !isImmediatelyPostCommentOnly)
+ {
+ isPrependPostBlockEmptyLineRequested = true;
+ }
+
+ if (isClosingHeader(currentHeader)
+ || foundClosingHeader)
+ {
+ isPrependPostBlockEmptyLineRequested = false;
+ }
+
+ if (shouldBreakClosingHeaderBlocks
+ && isCharImmediatelyPostCloseBlock
+ && !isImmediatelyPostCommentOnly
+ && !(currentHeader == &AS_WHILE // do-while
+ && foundClosingHeader))
+ {
+ isPrependPostBlockEmptyLineRequested = true;
+ }
+ }
+
+ if (currentHeader == &AS_CASE
+ || currentHeader == &AS_DEFAULT)
+ isInCase = true;
+
+ continue;
+ }
+ else if ((newHeader = findHeader(preDefinitionHeaders)) != nullptr
+ && parenStack->back() == 0
+ && !isInEnum) // not C++11 enum class
+ {
+ if (newHeader == &AS_NAMESPACE || newHeader == &AS_MODULE)
+ foundNamespaceHeader = true;
+ if (newHeader == &AS_CLASS)
+ foundClassHeader = true;
+ if (newHeader == &AS_STRUCT)
+ foundStructHeader = true;
+ if (newHeader == &AS_INTERFACE)
+ foundInterfaceHeader = true;
+ foundPreDefinitionHeader = true;
+ appendSequence(*newHeader);
+ goForward(newHeader->length() - 1);
+
+ continue;
+ }
+ else if ((newHeader = findHeader(preCommandHeaders)) != nullptr)
+ {
+ // a 'const' variable is not a preCommandHeader
+ if (previousNonWSChar == ')')
+ foundPreCommandHeader = true;
+ }
+ else if ((newHeader = findHeader(castOperators)) != nullptr)
+ {
+ foundCastOperator = true;
+ appendSequence(*newHeader);
+ goForward(newHeader->length() - 1);
+ continue;
+ }
+ } // (isPotentialHeader && !isInTemplate)
+
+ if (isInLineBreak) // OK to break line here
+ {
+ breakLine();
+ if (isInVirginLine) // adjust for the first line
+ {
+ lineCommentNoBeautify = lineCommentNoIndent;
+ lineCommentNoIndent = false;
+ if (isImmediatelyPostPreprocessor)
+ {
+ isInIndentablePreproc = isIndentableProprocessor;
+ isIndentableProprocessor = false;
+ }
+ }
+ }
+
+ if (previousNonWSChar == '}' || currentChar == ';')
+ {
+ if (currentChar == ';')
+ {
+ squareBracketCount = 0;
+
+ if (((shouldBreakOneLineStatements
+ || isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
+ && isOkToBreakBlock(braceTypeStack->back()))
+ && !(attachClosingBraceMode && peekNextChar() == '}'))
+ {
+ passedSemicolon = true;
+ }
+ else if (!shouldBreakOneLineStatements
+ && ASBeautifier::getNextWord(currentLine, charNum) == AS_ELSE)
+ {
+ // handle special case of "else" at the end of line
+ size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (ASBeautifier::peekNextChar(currentLine, nextText + 3) == ' ')
+ passedSemicolon = true;
+ }
+
+ if (shouldBreakBlocks
+ && currentHeader != nullptr
+ && currentHeader != &AS_CASE
+ && currentHeader != &AS_DEFAULT
+ && !isHeaderInMultiStatementLine
+ && parenStack->back() == 0)
+ {
+ isAppendPostBlockEmptyLineRequested = true;
+ }
+ }
+ if (currentChar != ';'
+ || (needHeaderOpeningBrace && parenStack->back() == 0))
+ currentHeader = nullptr;
+ resetEndOfStatement();
+ }
+
+ if (currentChar == ':'
+ && previousChar != ':' // not part of '::'
+ && peekNextChar() != ':') // not part of '::'
+ {
+ if (isInCase)
+ {
+ isInCase = false;
+ if (shouldBreakOneLineStatements)
+ passedColon = true;
+ }
+ else if (isCStyle() // for C/C++ only
+ && isOkToBreakBlock(braceTypeStack->back())
+ && shouldBreakOneLineStatements
+ && !foundQuestionMark // not in a ?: sequence
+ && !foundPreDefinitionHeader // not in a definition block
+ && previousCommandChar != ')' // not after closing paren of a method header
+ && !foundPreCommandHeader // not after a 'noexcept'
+ && squareBracketCount == 0 // not in objC method call
+ && !isInObjCMethodDefinition // not objC '-' or '+' method
+ && !isInObjCInterface // not objC @interface
+ && !isInObjCSelector // not objC @selector
+ && !isDigit(peekNextChar()) // not a bit field
+ && !isInEnum // not an enum with a base type
+ && !isInAsm // not in extended assembler
+ && !isInAsmOneLine // not in extended assembler
+ && !isInAsmBlock) // not in extended assembler
+ {
+ passedColon = true;
+ }
+
+ if (isCStyle()
+ && shouldPadMethodColon
+ && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector)
+ && !foundQuestionMark) // not in a ?: sequence
+ padObjCMethodColon();
+
+ if (isInObjCInterface)
+ {
+ appendSpacePad();
+ if ((int) currentLine.length() > charNum + 1
+ && !isWhiteSpace(currentLine[charNum + 1]))
+ currentLine.insert(charNum + 1, " ");
+ }
+
+ if (isClassInitializer())
+ isInClassInitializer = true;
+ }
+
+ if (currentChar == '?')
+ foundQuestionMark = true;
+
+ if (isPotentialHeader && !isInTemplate)
+ {
+ if (findKeyword(currentLine, charNum, AS_NEW)
+ || findKeyword(currentLine, charNum, AS_DELETE))
+ {
+ isInPotentialCalculation = false;
+ isImmediatelyPostNewDelete = true;
+ }
+
+ if (findKeyword(currentLine, charNum, AS_RETURN))
+ {
+ isInPotentialCalculation = true; // return is the same as an = sign
+ isImmediatelyPostReturn = true;
+ }
+
+ if (findKeyword(currentLine, charNum, AS_OPERATOR))
+ isImmediatelyPostOperator = true;
+
+ if (findKeyword(currentLine, charNum, AS_ENUM))
+ {
+ size_t firstNum = currentLine.find_first_of("(){},/");
+ if (firstNum == string::npos
+ || currentLine[firstNum] == '{'
+ || currentLine[firstNum] == '/')
+ isInEnum = true;
+ }
+
+ if (isCStyle()
+ && findKeyword(currentLine, charNum, AS_THROW)
+ && previousCommandChar != ')'
+ && !foundPreCommandHeader) // 'const' throw()
+ isImmediatelyPostThrow = true;
+
+ if (isCStyle() && findKeyword(currentLine, charNum, AS_EXTERN) && isExternC())
+ isInExternC = true;
+
+ if (isCStyle() && findKeyword(currentLine, charNum, AS_AUTO)
+ && (isBraceType(braceTypeStack->back(), NULL_TYPE)
+ || isBraceType(braceTypeStack->back(), NAMESPACE_TYPE)
+ || isBraceType(braceTypeStack->back(), CLASS_TYPE)))
+ foundTrailingReturnType = true;
+
+ // Objective-C NSException macros are preCommandHeaders
+ if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_DURING))
+ foundPreCommandMacro = true;
+ if (isCStyle() && findKeyword(currentLine, charNum, AS_NS_HANDLER))
+ foundPreCommandMacro = true;
+
+ if (isCStyle() && isExecSQL(currentLine, charNum))
+ isInExecSQL = true;
+
+ if (isCStyle())
+ {
+ if (findKeyword(currentLine, charNum, AS_ASM)
+ || findKeyword(currentLine, charNum, AS__ASM__))
+ {
+ isInAsm = true;
+ }
+ else if (findKeyword(currentLine, charNum, AS_MS_ASM) // microsoft specific
+ || findKeyword(currentLine, charNum, AS_MS__ASM))
+ {
+ int index = 4;
+ if (peekNextChar() == '_') // check for __asm
+ index = 5;
+
+ char peekedChar = ASBase::peekNextChar(currentLine, charNum + index);
+ if (peekedChar == '{' || peekedChar == ' ')
+ isInAsmBlock = true;
+ else
+ isInAsmOneLine = true;
+ }
+ }
+
+ if (isJavaStyle()
+ && (findKeyword(currentLine, charNum, AS_STATIC)
+ && isNextCharOpeningBrace(charNum + 6)))
+ isJavaStaticConstructor = true;
+
+ if (isSharpStyle()
+ && (findKeyword(currentLine, charNum, AS_DELEGATE)
+ || findKeyword(currentLine, charNum, AS_UNCHECKED)))
+ isSharpDelegate = true;
+
+ // append the entire name
+ string name = getCurrentWord(currentLine, charNum);
+ // must pad the 'and' and 'or' operators if required
+ if (name == "and" || name == "or")
+ {
+ if (shouldPadOperators && previousNonWSChar != ':')
+ {
+ appendSpacePad();
+ appendOperator(name);
+ goForward(name.length() - 1);
+ if (!isBeforeAnyComment()
+ && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0)
+ && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0))
+ appendSpaceAfter();
+ }
+ else
+ {
+ appendOperator(name);
+ goForward(name.length() - 1);
+ }
+ }
+ else
+ {
+ appendSequence(name);
+ goForward(name.length() - 1);
+ }
+
+ continue;
+
+ } // (isPotentialHeader && !isInTemplate)
+
+ // determine if this is an Objective-C statement
+
+ if (currentChar == '@'
+ && isCharPotentialHeader(currentLine, charNum + 1)
+ && findKeyword(currentLine, charNum + 1, AS_INTERFACE)
+ && isBraceType(braceTypeStack->back(), NULL_TYPE))
+ {
+ isInObjCInterface = true;
+ string name = '@' + AS_INTERFACE;
+ appendSequence(name);
+ goForward(name.length() - 1);
+ continue;
+ }
+ else if (currentChar == '@'
+ && isCharPotentialHeader(currentLine, charNum + 1)
+ && findKeyword(currentLine, charNum + 1, AS_SELECTOR))
+ {
+ isInObjCSelector = true;
+ string name = '@' + AS_SELECTOR;
+ appendSequence(name);
+ goForward(name.length() - 1);
+ continue;
+ }
+ else if ((currentChar == '-' || currentChar == '+')
+ && (int) currentLine.find_first_not_of(" \t") == charNum
+ && peekNextChar() == '('
+ && isBraceType(braceTypeStack->back(), NULL_TYPE)
+ && !isInPotentialCalculation)
+ {
+ isInObjCMethodDefinition = true;
+ isImmediatelyPostObjCMethodPrefix = true;
+ isInObjCInterface = false;
+ if (getAlignMethodColon())
+ objCColonAlign = findObjCColonAlignment();
+ appendCurrentChar();
+ continue;
+ }
+
+ // determine if this is a potential calculation
+
+ bool isPotentialOperator = isCharPotentialOperator(currentChar);
+ newHeader = nullptr;
+
+ if (isPotentialOperator)
+ {
+ newHeader = findOperator(operators);
+
+ // check for Java ? wildcard
+ if (newHeader != nullptr
+ && newHeader == &AS_GCC_MIN_ASSIGN
+ && isJavaStyle()
+ && isInTemplate)
+ newHeader = nullptr;
+
+ if (newHeader != nullptr)
+ {
+ if (newHeader == &AS_LAMBDA)
+ foundPreCommandHeader = true;
+
+ // correct mistake of two >> closing a template
+ if (isInTemplate && (newHeader == &AS_GR_GR || newHeader == &AS_GR_GR_GR))
+ newHeader = &AS_GR;
+
+ if (!isInPotentialCalculation)
+ {
+ // must determine if newHeader is an assignment operator
+ // do NOT use findOperator - the length must be exact!!!
+ if (find(begin(*assignmentOperators), end(*assignmentOperators), newHeader)
+ != end(*assignmentOperators))
+ {
+ foundPreCommandHeader = false;
+ char peekedChar = peekNextChar();
+ isInPotentialCalculation = !(newHeader == &AS_EQUAL && peekedChar == '*')
+ && !(newHeader == &AS_EQUAL && peekedChar == '&')
+ && !isCharImmediatelyPostOperator;
+ }
+ }
+ }
+ }
+
+ // process pointers and references
+ // check newHeader to eliminate things like '&&' sequence
+ if (newHeader != nullptr && !isJavaStyle()
+ && (newHeader == &AS_MULT
+ || newHeader == &AS_BIT_AND
+ || newHeader == &AS_BIT_XOR
+ || newHeader == &AS_AND)
+ && isPointerOrReference())
+ {
+ if (!isDereferenceOrAddressOf() && !isOperatorPaddingDisabled())
+ formatPointerOrReference();
+ else
+ {
+ appendOperator(*newHeader);
+ goForward(newHeader->length() - 1);
+ }
+ isImmediatelyPostPointerOrReference = true;
+ continue;
+ }
+
+ if (shouldPadOperators && newHeader != nullptr && !isOperatorPaddingDisabled())
+ {
+ padOperators(newHeader);
+ continue;
+ }
+
+ // remove spaces before commas
+ if (currentChar == ',')
+ {
+ const size_t len = formattedLine.length();
+ size_t lastText = formattedLine.find_last_not_of(' ');
+ if (lastText != string::npos && lastText < len - 1)
+ {
+ formattedLine.resize(lastText + 1);
+ int size_diff = len - (lastText + 1);
+ spacePadNum -= size_diff;
+ }
+ }
+
+ // pad commas and semi-colons
+ if (currentChar == ';'
+ || (currentChar == ',' && (shouldPadOperators || shouldPadCommas)))
+ {
+ char nextChar = ' ';
+ if (charNum + 1 < (int) currentLine.length())
+ nextChar = currentLine[charNum + 1];
+ if (!isWhiteSpace(nextChar)
+ && nextChar != '}'
+ && nextChar != ')'
+ && nextChar != ']'
+ && nextChar != '>'
+ && nextChar != ';'
+ && !isBeforeAnyComment()
+ /* && !(isBraceType(braceTypeStack->back(), ARRAY_TYPE)) */
+ )
+ {
+ appendCurrentChar();
+ appendSpaceAfter();
+ continue;
+ }
+ }
+
+ // pad parens
+ if (currentChar == '(' || currentChar == ')')
+ {
+ if (currentChar == '(')
+ {
+ if (shouldPadHeader
+ && (isCharImmediatelyPostReturn
+ || isCharImmediatelyPostThrow
+ || isCharImmediatelyPostNewDelete))
+ appendSpacePad();
+ }
+
+ if (shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen)
+ padParens();
+ else
+ appendCurrentChar();
+
+ if (isInObjCMethodDefinition)
+ {
+ if (currentChar == '(' && isImmediatelyPostObjCMethodPrefix)
+ {
+ if (shouldPadMethodPrefix || shouldUnPadMethodPrefix)
+ padObjCMethodPrefix();
+ isImmediatelyPostObjCMethodPrefix = false;
+ isInObjCReturnType = true;
+ }
+ else if (currentChar == ')' && isInObjCReturnType)
+ {
+ if (shouldPadReturnType || shouldUnPadReturnType)
+ padObjCReturnType();
+ isInObjCReturnType = false;
+ }
+ else if (shouldPadParamType || shouldUnPadParamType)
+ padObjCParamType();
+ }
+ continue;
+ }
+
+ // bypass the entire operator
+ if (newHeader != nullptr)
+ {
+ appendOperator(*newHeader);
+ goForward(newHeader->length() - 1);
+ continue;
+ }
+
+ appendCurrentChar();
+
+ } // end of while loop * end of while loop * end of while loop * end of while loop
+
+ // return a beautified (i.e. correctly indented) line.
+
+ string beautifiedLine;
+ size_t readyFormattedLineLength = trim(readyFormattedLine).length();
+ bool isInNamespace = isBraceType(braceTypeStack->back(), NAMESPACE_TYPE);
+
+ if (prependEmptyLine // prepend a blank line before this formatted line
+ && readyFormattedLineLength > 0
+ && previousReadyFormattedLineLength > 0)
+ {
+ isLineReady = true; // signal a waiting readyFormattedLine
+ beautifiedLine = beautify("");
+ previousReadyFormattedLineLength = 0;
+ // call the enhancer for new empty lines
+ enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);
+ }
+ else // format the current formatted line
+ {
+ isLineReady = false;
+ runInIndentContinuation = runInIndentChars;
+ beautifiedLine = beautify(readyFormattedLine);
+ previousReadyFormattedLineLength = readyFormattedLineLength;
+ // the enhancer is not called for no-indent line comments
+ if (!lineCommentNoBeautify && !isFormattingModeOff)
+ enhancer->enhance(beautifiedLine, isInNamespace, isInPreprocessorBeautify, isInBeautifySQL);
+ runInIndentChars = 0;
+ lineCommentNoBeautify = lineCommentNoIndent;
+ lineCommentNoIndent = false;
+ isInIndentablePreproc = isIndentableProprocessor;
+ isIndentableProprocessor = false;
+ isElseHeaderIndent = elseHeaderFollowsComments;
+ isCaseHeaderCommentIndent = caseHeaderFollowsComments;
+ objCColonAlignSubsequent = objCColonAlign;
+ if (isCharImmediatelyPostNonInStmt)
+ {
+ isNonInStatementArray = false;
+ isCharImmediatelyPostNonInStmt = false;
+ }
+ isInPreprocessorBeautify = isInPreprocessor; // used by ASEnhancer
+ isInBeautifySQL = isInExecSQL; // used by ASEnhancer
+ }
+
+ prependEmptyLine = false;
+ assert(computeChecksumOut(beautifiedLine));
+ return beautifiedLine;
+}
+
+/**
+ * check if there are any indented lines ready to be read by nextLine()
+ *
+ * @return are there any indented lines ready?
+ */
+bool ASFormatter::hasMoreLines() const
+{
+ return !endOfCodeReached;
+}
+
+/**
+ * comparison function for BraceType enum
+ */
+bool ASFormatter::isBraceType(BraceType a, BraceType b) const
+{
+ if (a == NULL_TYPE || b == NULL_TYPE)
+ return (a == b);
+ return ((a & b) == b);
+}
+
+/**
+ * set the formatting style.
+ *
+ * @param style the formatting style.
+ */
+void ASFormatter::setFormattingStyle(FormatStyle style)
+{
+ formattingStyle = style;
+}
+
+/**
+ * set the add braces mode.
+ * options:
+ * true braces added to headers for single line statements.
+ * false braces NOT added to headers for single line statements.
+ *
+ * @param state the add braces state.
+ */
+void ASFormatter::setAddBracesMode(bool state)
+{
+ shouldAddBraces = state;
+}
+
+/**
+ * set the add one line braces mode.
+ * options:
+ * true one line braces added to headers for single line statements.
+ * false one line braces NOT added to headers for single line statements.
+ *
+ * @param state the add one line braces state.
+ */
+void ASFormatter::setAddOneLineBracesMode(bool state)
+{
+ shouldAddBraces = state;
+ shouldAddOneLineBraces = state;
+}
+
+/**
+ * set the remove braces mode.
+ * options:
+ * true braces removed from headers for single line statements.
+ * false braces NOT removed from headers for single line statements.
+ *
+ * @param state the remove braces state.
+ */
+void ASFormatter::setRemoveBracesMode(bool state)
+{
+ shouldRemoveBraces = state;
+}
+
+// retained for compatability with release 2.06
+// "Brackets" have been changed to "Braces" in 3.0
+// it is referenced only by the old "bracket" options
+void ASFormatter::setAddBracketsMode(bool state)
+{
+ setAddBracesMode(state);
+}
+
+// retained for compatability with release 2.06
+// "Brackets" have been changed to "Braces" in 3.0
+// it is referenced only by the old "bracket" options
+void ASFormatter::setAddOneLineBracketsMode(bool state)
+{
+ setAddOneLineBracesMode(state);
+}
+
+// retained for compatability with release 2.06
+// "Brackets" have been changed to "Braces" in 3.0
+// it is referenced only by the old "bracket" options
+void ASFormatter::setRemoveBracketsMode(bool state)
+{
+ setRemoveBracesMode(state);
+}
+
+// retained for compatability with release 2.06
+// "Brackets" have been changed to "Braces" in 3.0
+// it is referenced only by the old "bracket" options
+void ASFormatter::setBreakClosingHeaderBracketsMode(bool state)
+{
+ setBreakClosingHeaderBracesMode(state);
+}
+
+
+/**
+ * set the brace formatting mode.
+ * options:
+ *
+ * @param mode the brace formatting mode.
+ */
+void ASFormatter::setBraceFormatMode(BraceMode mode)
+{
+ braceFormatMode = mode;
+}
+
+/**
+ * set 'break after' mode for maximum code length
+ *
+ * @param state the 'break after' mode.
+ */
+void ASFormatter::setBreakAfterMode(bool state)
+{
+ shouldBreakLineAfterLogical = state;
+}
+
+/**
+ * set closing header brace breaking mode
+ * options:
+ * true braces just before closing headers (e.g. 'else', 'catch')
+ * will be broken, even if standard braces are attached.
+ * false closing header braces will be treated as standard braces.
+ *
+ * @param state the closing header brace breaking mode.
+ */
+void ASFormatter::setBreakClosingHeaderBracesMode(bool state)
+{
+ shouldBreakClosingHeaderBraces = state;
+}
+
+/**
+ * set 'else if()' breaking mode
+ * options:
+ * true 'else' headers will be broken from their succeeding 'if' headers.
+ * false 'else' headers will be attached to their succeeding 'if' headers.
+ *
+ * @param state the 'else if()' breaking mode.
+ */
+void ASFormatter::setBreakElseIfsMode(bool state)
+{
+ shouldBreakElseIfs = state;
+}
+
+/**
+* set comma padding mode.
+* options:
+* true statement commas and semicolons will be padded with spaces around them.
+* false statement commas and semicolons will not be padded.
+*
+* @param state the padding mode.
+*/
+void ASFormatter::setCommaPaddingMode(bool state)
+{
+ shouldPadCommas = state;
+}
+
+/**
+ * set maximum code length
+ *
+ * @param max the maximum code length.
+ */
+void ASFormatter::setMaxCodeLength(int max)
+{
+ maxCodeLength = max;
+}
+
+/**
+ * set operator padding mode.
+ * options:
+ * true statement operators will be padded with spaces around them.
+ * false statement operators will not be padded.
+ *
+ * @param state the padding mode.
+ */
+void ASFormatter::setOperatorPaddingMode(bool state)
+{
+ shouldPadOperators = state;
+}
+
+/**
+ * set parenthesis outside padding mode.
+ * options:
+ * true statement parentheses will be padded with spaces around them.
+ * false statement parentheses will not be padded.
+ *
+ * @param state the padding mode.
+ */
+void ASFormatter::setParensOutsidePaddingMode(bool state)
+{
+ shouldPadParensOutside = state;
+}
+
+/**
+ * set parenthesis inside padding mode.
+ * options:
+ * true statement parenthesis will be padded with spaces around them.
+ * false statement parenthesis will not be padded.
+ *
+ * @param state the padding mode.
+ */
+void ASFormatter::setParensInsidePaddingMode(bool state)
+{
+ shouldPadParensInside = state;
+}
+
+/**
+ * set padding mode before one or more open parentheses.
+ * options:
+ * true first open parenthesis will be padded with a space before.
+ * false first open parenthesis will not be padded.
+ *
+ * @param state the padding mode.
+ */
+void ASFormatter::setParensFirstPaddingMode(bool state)
+{
+ shouldPadFirstParen = state;
+}
+
+/**
+ * set header padding mode.
+ * options:
+ * true headers will be padded with spaces around them.
+ * false headers will not be padded.
+ *
+ * @param state the padding mode.
+ */
+void ASFormatter::setParensHeaderPaddingMode(bool state)
+{
+ shouldPadHeader = state;
+}
+
+/**
+ * set parenthesis unpadding mode.
+ * options:
+ * true statement parenthesis will be unpadded with spaces removed around them.
+ * false statement parenthesis will not be unpadded.
+ *
+ * @param state the padding mode.
+ */
+void ASFormatter::setParensUnPaddingMode(bool state)
+{
+ shouldUnPadParens = state;
+}
+
+/**
+* set the state of the preprocessor indentation option.
+* If true, #ifdef blocks at level 0 will be indented.
+*
+* @param state state of option.
+*/
+void ASFormatter::setPreprocBlockIndent(bool state)
+{
+ shouldIndentPreprocBlock = state;
+}
+
+/**
+ * Set strip comment prefix mode.
+ * options:
+ * true strip leading '*' in a comment.
+ * false leading '*' in a comment will be left unchanged.
+ *
+ * @param state the strip comment prefix mode.
+ */
+void ASFormatter::setStripCommentPrefix(bool state)
+{
+ shouldStripCommentPrefix = state;
+}
+
+/**
+ * set objective-c '-' or '+' class prefix padding mode.
+ * options:
+ * true class prefix will be padded a spaces after them.
+ * false class prefix will be left unchanged.
+ *
+ * @param state the padding mode.
+ */
+void ASFormatter::setMethodPrefixPaddingMode(bool state)
+{
+ shouldPadMethodPrefix = state;
+}
+
+/**
+ * set objective-c '-' or '+' class prefix unpadding mode.
+ * options:
+ * true class prefix will be unpadded with spaces after them removed.
+ * false class prefix will left unchanged.
+ *
+ * @param state the unpadding mode.
+ */
+void ASFormatter::setMethodPrefixUnPaddingMode(bool state)
+{
+ shouldUnPadMethodPrefix = state;
+}
+
+// set objective-c '-' or '+' return type padding mode.
+void ASFormatter::setReturnTypePaddingMode(bool state)
+{
+ shouldPadReturnType = state;
+}
+
+// set objective-c '-' or '+' return type unpadding mode.
+void ASFormatter::setReturnTypeUnPaddingMode(bool state)
+{
+ shouldUnPadReturnType = state;
+}
+
+// set objective-c method parameter type padding mode.
+void ASFormatter::setParamTypePaddingMode(bool state)
+{
+ shouldPadParamType = state;
+}
+
+// set objective-c method parameter type unpadding mode.
+void ASFormatter::setParamTypeUnPaddingMode(bool state)
+{
+ shouldUnPadParamType = state;
+}
+
+/**
+ * set objective-c method colon padding mode.
+ *
+ * @param mode objective-c colon padding mode.
+ */
+void ASFormatter::setObjCColonPaddingMode(ObjCColonPad mode)
+{
+ shouldPadMethodColon = true;
+ objCColonPadMode = mode;
+}
+
+/**
+ * set option to attach closing braces
+ *
+ * @param state true = attach, false = don't attach.
+ */
+void ASFormatter::setAttachClosingBraceMode(bool state)
+{
+ attachClosingBraceMode = state;
+}
+
+/**
+ * set option to attach class braces
+ *
+ * @param state true = attach, false = use style default.
+ */
+void ASFormatter::setAttachClass(bool state)
+{
+ shouldAttachClass = state;
+}
+
+/**
+ * set option to attach extern "C" braces
+ *
+ * @param state true = attach, false = use style default.
+ */
+void ASFormatter::setAttachExternC(bool state)
+{
+ shouldAttachExternC = state;
+}
+
+/**
+ * set option to attach namespace braces
+ *
+ * @param state true = attach, false = use style default.
+ */
+void ASFormatter::setAttachNamespace(bool state)
+{
+ shouldAttachNamespace = state;
+}
+
+/**
+ * set option to attach inline braces
+ *
+ * @param state true = attach, false = use style default.
+ */
+void ASFormatter::setAttachInline(bool state)
+{
+ shouldAttachInline = state;
+}
+
+void ASFormatter::setAttachClosingWhile(bool state)
+{
+ shouldAttachClosingWhile = state;
+}
+
+/**
+ * set option to break/not break one-line blocks
+ *
+ * @param state true = break, false = don't break.
+ */
+void ASFormatter::setBreakOneLineBlocksMode(bool state)
+{
+ shouldBreakOneLineBlocks = state;
+}
+
+/**
+* set one line headers breaking mode
+*/
+void ASFormatter::setBreakOneLineHeadersMode(bool state)
+{
+ shouldBreakOneLineHeaders = state;
+}
+
+/**
+* set option to break/not break lines consisting of multiple statements.
+*
+* @param state true = break, false = don't break.
+*/
+void ASFormatter::setBreakOneLineStatementsMode(bool state)
+{
+ shouldBreakOneLineStatements = state;
+}
+
+void ASFormatter::setCloseTemplatesMode(bool state)
+{
+ shouldCloseTemplates = state;
+}
+
+/**
+ * set option to convert tabs to spaces.
+ *
+ * @param state true = convert, false = don't convert.
+ */
+void ASFormatter::setTabSpaceConversionMode(bool state)
+{
+ shouldConvertTabs = state;
+}
+
+/**
+ * set option to indent comments in column 1.
+ *
+ * @param state true = indent, false = don't indent.
+ */
+void ASFormatter::setIndentCol1CommentsMode(bool state)
+{
+ shouldIndentCol1Comments = state;
+}
+
+/**
+ * set option to force all line ends to a particular style.
+ *
+ * @param fmt format enum value
+ */
+void ASFormatter::setLineEndFormat(LineEndFormat fmt)
+{
+ lineEnd = fmt;
+}
+
+/**
+ * set option to break unrelated blocks of code with empty lines.
+ *
+ * @param state true = convert, false = don't convert.
+ */
+void ASFormatter::setBreakBlocksMode(bool state)
+{
+ shouldBreakBlocks = state;
+}
+
+/**
+ * set option to break closing header blocks of code (such as 'else', 'catch', ...) with empty lines.
+ *
+ * @param state true = convert, false = don't convert.
+ */
+void ASFormatter::setBreakClosingHeaderBlocksMode(bool state)
+{
+ shouldBreakClosingHeaderBlocks = state;
+}
+
+/**
+ * set option to delete empty lines.
+ *
+ * @param state true = delete, false = don't delete.
+ */
+void ASFormatter::setDeleteEmptyLinesMode(bool state)
+{
+ shouldDeleteEmptyLines = state;
+}
+
+/**
+ * set the pointer alignment.
+ *
+ * @param alignment the pointer alignment.
+ */
+void ASFormatter::setPointerAlignment(PointerAlign alignment)
+{
+ pointerAlignment = alignment;
+}
+
+void ASFormatter::setReferenceAlignment(ReferenceAlign alignment)
+{
+ referenceAlignment = alignment;
+}
+
+/**
+ * jump over several characters.
+ *
+ * @param i the number of characters to jump over.
+ */
+void ASFormatter::goForward(int i)
+{
+ while (--i >= 0)
+ getNextChar();
+}
+
+/**
+ * peek at the next unread character.
+ *
+ * @return the next unread character.
+ */
+char ASFormatter::peekNextChar() const
+{
+ char ch = ' ';
+ size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
+
+ if (peekNum == string::npos)
+ return ch;
+
+ ch = currentLine[peekNum];
+
+ return ch;
+}
+
+/**
+ * check if current placement is before a comment
+ *
+ * @return is before a comment.
+ */
+bool ASFormatter::isBeforeComment() const
+{
+ bool foundComment = false;
+ size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
+
+ if (peekNum == string::npos)
+ return foundComment;
+
+ foundComment = (currentLine.compare(peekNum, 2, "/*") == 0);
+
+ return foundComment;
+}
+
+/**
+ * check if current placement is before a comment or line-comment
+ *
+ * @return is before a comment or line-comment.
+ */
+bool ASFormatter::isBeforeAnyComment() const
+{
+ bool foundComment = false;
+ size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
+
+ if (peekNum == string::npos)
+ return foundComment;
+
+ foundComment = (currentLine.compare(peekNum, 2, "/*") == 0
+ || currentLine.compare(peekNum, 2, "//") == 0);
+
+ return foundComment;
+}
+
+/**
+ * check if current placement is before a comment or line-comment
+ * if a block comment it must be at the end of the line
+ *
+ * @return is before a comment or line-comment.
+ */
+bool ASFormatter::isBeforeAnyLineEndComment(int startPos) const
+{
+ bool foundLineEndComment = false;
+ size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
+
+ if (peekNum != string::npos)
+ {
+ if (currentLine.compare(peekNum, 2, "//") == 0)
+ foundLineEndComment = true;
+ else if (currentLine.compare(peekNum, 2, "/*") == 0)
+ {
+ // comment must be closed on this line with nothing after it
+ size_t endNum = currentLine.find("*/", peekNum + 2);
+ if (endNum != string::npos)
+ {
+ size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
+ if (nextChar == string::npos)
+ foundLineEndComment = true;
+ }
+ }
+ }
+ return foundLineEndComment;
+}
+
+/**
+ * check if current placement is before a comment followed by a line-comment
+ *
+ * @return is before a multiple line-end comment.
+ */
+bool ASFormatter::isBeforeMultipleLineEndComments(int startPos) const
+{
+ bool foundMultipleLineEndComment = false;
+ size_t peekNum = currentLine.find_first_not_of(" \t", startPos + 1);
+
+ if (peekNum != string::npos)
+ {
+ if (currentLine.compare(peekNum, 2, "/*") == 0)
+ {
+ // comment must be closed on this line with nothing after it
+ size_t endNum = currentLine.find("*/", peekNum + 2);
+ if (endNum != string::npos)
+ {
+ size_t nextChar = currentLine.find_first_not_of(" \t", endNum + 2);
+ if (nextChar != string::npos
+ && currentLine.compare(nextChar, 2, "//") == 0)
+ foundMultipleLineEndComment = true;
+ }
+ }
+ }
+ return foundMultipleLineEndComment;
+}
+
+/**
+ * get the next character, increasing the current placement in the process.
+ * the new character is inserted into the variable currentChar.
+ *
+ * @return whether succeeded to receive the new character.
+ */
+bool ASFormatter::getNextChar()
+{
+ isInLineBreak = false;
+ previousChar = currentChar;
+
+ if (!isWhiteSpace(currentChar))
+ {
+ previousNonWSChar = currentChar;
+ if (!isInComment && !isInLineComment && !isInQuote
+ && !isImmediatelyPostComment
+ && !isImmediatelyPostLineComment
+ && !isInPreprocessor
+ && !isSequenceReached("/*")
+ && !isSequenceReached("//"))
+ previousCommandChar = currentChar;
+ }
+
+ if (charNum + 1 < (int) currentLine.length()
+ && (!isWhiteSpace(peekNextChar()) || isInComment || isInLineComment))
+ {
+ currentChar = currentLine[++charNum];
+
+ if (currentChar == '\t' && shouldConvertTabs)
+ convertTabToSpaces();
+
+ return true;
+ }
+
+ // end of line has been reached
+ return getNextLine();
+}
+
+/**
+ * get the next line of input, increasing the current placement in the process.
+ *
+ * @param emptyLineWasDeleted an empty line was deleted.
+ * @return whether succeeded in reading the next line.
+ */
+bool ASFormatter::getNextLine(bool emptyLineWasDeleted /*false*/)
+{
+ if (!sourceIterator->hasMoreLines())
+ {
+ endOfCodeReached = true;
+ return false;
+ }
+ if (appendOpeningBrace)
+ currentLine = "{"; // append brace that was removed from the previous line
+ else
+ {
+ currentLine = sourceIterator->nextLine(emptyLineWasDeleted);
+ assert(computeChecksumIn(currentLine));
+ }
+ // reset variables for new line
+ inLineNumber++;
+ if (endOfAsmReached)
+ endOfAsmReached = isInAsmBlock = isInAsm = false;
+ shouldKeepLineUnbroken = false;
+ isInCommentStartLine = false;
+ isInCase = false;
+ isInAsmOneLine = false;
+ isHeaderInMultiStatementLine = false;
+ isInQuoteContinuation = isInVerbatimQuote || haveLineContinuationChar;
+ haveLineContinuationChar = false;
+ isImmediatelyPostEmptyLine = lineIsEmpty;
+ previousChar = ' ';
+
+ if (currentLine.length() == 0)
+ currentLine = string(" "); // a null is inserted if this is not done
+
+ // unless reading in the first line of the file, break a new line.
+ if (!isVirgin)
+ isInLineBreak = true;
+ else
+ isVirgin = false;
+
+ if (isImmediatelyPostNonInStmt)
+ {
+ isCharImmediatelyPostNonInStmt = true;
+ isImmediatelyPostNonInStmt = false;
+ }
+
+ // check if is in preprocessor before line trimming
+ // a blank line after a \ will remove the flag
+ isImmediatelyPostPreprocessor = isInPreprocessor;
+ if (!isInComment
+ && (previousNonWSChar != '\\'
+ || isEmptyLine(currentLine)))
+ isInPreprocessor = false;
+
+ if (passedSemicolon)
+ isInExecSQL = false;
+ initNewLine();
+
+ currentChar = currentLine[charNum];
+ if (isInBraceRunIn && previousNonWSChar == '{' && !isInComment)
+ isInLineBreak = false;
+ isInBraceRunIn = false;
+
+ if (currentChar == '\t' && shouldConvertTabs)
+ convertTabToSpaces();
+
+ // check for an empty line inside a command brace.
+ // if yes then read the next line (calls getNextLine recursively).
+ // must be after initNewLine.
+ if (shouldDeleteEmptyLines
+ && lineIsEmpty
+ && isBraceType((*braceTypeStack)[braceTypeStack->size() - 1], COMMAND_TYPE))
+ {
+ if (!shouldBreakBlocks || previousNonWSChar == '{' || !commentAndHeaderFollows())
+ {
+ isInPreprocessor = isImmediatelyPostPreprocessor; // restore
+ lineIsEmpty = false;
+ return getNextLine(true);
+ }
+ }
+ return true;
+}
+
+/**
+ * jump over the leading white space in the current line,
+ * IF the line does not begin a comment or is in a preprocessor definition.
+ */
+void ASFormatter::initNewLine()
+{
+ size_t len = currentLine.length();
+ size_t tabSize = getTabLength();
+ charNum = 0;
+
+ // don't trim these
+ if (isInQuoteContinuation
+ || (isInPreprocessor && !getPreprocDefineIndent()))
+ return;
+
+ // SQL continuation lines must be adjusted so the leading spaces
+ // is equivalent to the opening EXEC SQL
+ if (isInExecSQL)
+ {
+ // replace leading tabs with spaces
+ // so that continuation indent will be spaces
+ size_t tabCount_ = 0;
+ size_t i;
+ for (i = 0; i < currentLine.length(); i++)
+ {
+ if (!isWhiteSpace(currentLine[i])) // stop at first text
+ break;
+ if (currentLine[i] == '\t')
+ {
+ size_t numSpaces = tabSize - ((tabCount_ + i) % tabSize);
+ currentLine.replace(i, 1, numSpaces, ' ');
+ tabCount_++;
+ i += tabSize - 1;
+ }
+ }
+ // this will correct the format if EXEC SQL is not a hanging indent
+ trimContinuationLine();
+ return;
+ }
+
+ // comment continuation lines must be adjusted so the leading spaces
+ // is equivalent to the opening comment
+ if (isInComment)
+ {
+ if (noTrimCommentContinuation)
+ leadingSpaces = tabIncrementIn = 0;
+ trimContinuationLine();
+ return;
+ }
+
+ // compute leading spaces
+ isImmediatelyPostCommentOnly = lineIsLineCommentOnly || lineEndsInCommentOnly;
+ lineIsCommentOnly = false;
+ lineIsLineCommentOnly = false;
+ lineEndsInCommentOnly = false;
+ doesLineStartComment = false;
+ currentLineBeginsWithBrace = false;
+ lineIsEmpty = false;
+ currentLineFirstBraceNum = string::npos;
+ tabIncrementIn = 0;
+
+ // bypass whitespace at the start of a line
+ // preprocessor tabs are replaced later in the program
+ for (charNum = 0; isWhiteSpace(currentLine[charNum]) && charNum + 1 < (int) len; charNum++)
+ {
+ if (currentLine[charNum] == '\t' && !isInPreprocessor)
+ tabIncrementIn += tabSize - 1 - ((tabIncrementIn + charNum) % tabSize);
+ }
+ leadingSpaces = charNum + tabIncrementIn;
+
+ if (isSequenceReached("/*"))
+ {
+ doesLineStartComment = true;
+ if ((int) currentLine.length() > charNum + 2
+ && currentLine.find("*/", charNum + 2) != string::npos)
+ lineIsCommentOnly = true;
+ }
+ else if (isSequenceReached("//"))
+ {
+ lineIsLineCommentOnly = true;
+ }
+ else if (isSequenceReached("{"))
+ {
+ currentLineBeginsWithBrace = true;
+ currentLineFirstBraceNum = charNum;
+ size_t firstText = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (firstText != string::npos)
+ {
+ if (currentLine.compare(firstText, 2, "//") == 0)
+ lineIsLineCommentOnly = true;
+ else if (currentLine.compare(firstText, 2, "/*") == 0
+ || isExecSQL(currentLine, firstText))
+ {
+ // get the extra adjustment
+ size_t j;
+ for (j = charNum + 1; j < firstText && isWhiteSpace(currentLine[j]); j++)
+ {
+ if (currentLine[j] == '\t')
+ tabIncrementIn += tabSize - 1 - ((tabIncrementIn + j) % tabSize);
+ }
+ leadingSpaces = j + tabIncrementIn;
+ if (currentLine.compare(firstText, 2, "/*") == 0)
+ doesLineStartComment = true;
+ }
+ }
+ }
+ else if (isWhiteSpace(currentLine[charNum]) && !(charNum + 1 < (int) currentLine.length()))
+ {
+ lineIsEmpty = true;
+ }
+
+ // do not trim indented preprocessor define (except for comment continuation lines)
+ if (isInPreprocessor)
+ {
+ if (!doesLineStartComment)
+ leadingSpaces = 0;
+ charNum = 0;
+ }
+}
+
+/**
+ * Append a character to the current formatted line.
+ * The formattedLine split points are updated.
+ *
+ * @param ch the character to append.
+ * @param canBreakLine if true, a registered line-break
+ */
+void ASFormatter::appendChar(char ch, bool canBreakLine)
+{
+ if (canBreakLine && isInLineBreak)
+ breakLine();
+
+ formattedLine.append(1, ch);
+ isImmediatelyPostCommentOnly = false;
+ if (maxCodeLength != string::npos)
+ {
+ // These compares reduce the frequency of function calls.
+ if (isOkToSplitFormattedLine())
+ updateFormattedLineSplitPoints(ch);
+ if (formattedLine.length() > maxCodeLength)
+ testForTimeToSplitFormattedLine();
+ }
+}
+
+/**
+ * Append a string sequence to the current formatted line.
+ * The formattedLine split points are NOT updated.
+ * But the formattedLine is checked for time to split.
+ *
+ * @param sequence the sequence to append.
+ * @param canBreakLine if true, a registered line-break
+ */
+void ASFormatter::appendSequence(const string& sequence, bool canBreakLine)
+{
+ if (canBreakLine && isInLineBreak)
+ breakLine();
+ formattedLine.append(sequence);
+ if (formattedLine.length() > maxCodeLength)
+ testForTimeToSplitFormattedLine();
+}
+
+/**
+ * Append an operator sequence to the current formatted line.
+ * The formattedLine split points are updated.
+ *
+ * @param sequence the sequence to append.
+ * @param canBreakLine if true, a registered line-break
+ */
+void ASFormatter::appendOperator(const string& sequence, bool canBreakLine)
+{
+ if (canBreakLine && isInLineBreak)
+ breakLine();
+ formattedLine.append(sequence);
+ if (maxCodeLength != string::npos)
+ {
+ // These compares reduce the frequency of function calls.
+ if (isOkToSplitFormattedLine())
+ updateFormattedLineSplitPointsOperator(sequence);
+ if (formattedLine.length() > maxCodeLength)
+ testForTimeToSplitFormattedLine();
+ }
+}
+
+/**
+ * append a space to the current formattedline, UNLESS the
+ * last character is already a white-space character.
+ */
+void ASFormatter::appendSpacePad()
+{
+ int len = formattedLine.length();
+ if (len > 0 && !isWhiteSpace(formattedLine[len - 1]))
+ {
+ formattedLine.append(1, ' ');
+ spacePadNum++;
+ if (maxCodeLength != string::npos)
+ {
+ // These compares reduce the frequency of function calls.
+ if (isOkToSplitFormattedLine())
+ updateFormattedLineSplitPoints(' ');
+ if (formattedLine.length() > maxCodeLength)
+ testForTimeToSplitFormattedLine();
+ }
+ }
+}
+
+/**
+ * append a space to the current formattedline, UNLESS the
+ * next character is already a white-space character.
+ */
+void ASFormatter::appendSpaceAfter()
+{
+ int len = currentLine.length();
+ if (charNum + 1 < len && !isWhiteSpace(currentLine[charNum + 1]))
+ {
+ formattedLine.append(1, ' ');
+ spacePadNum++;
+ if (maxCodeLength != string::npos)
+ {
+ // These compares reduce the frequency of function calls.
+ if (isOkToSplitFormattedLine())
+ updateFormattedLineSplitPoints(' ');
+ if (formattedLine.length() > maxCodeLength)
+ testForTimeToSplitFormattedLine();
+ }
+ }
+}
+
+/**
+ * register a line break for the formatted line.
+ */
+void ASFormatter::breakLine(bool isSplitLine /*false*/)
+{
+ isLineReady = true;
+ isInLineBreak = false;
+ spacePadNum = nextLineSpacePadNum;
+ nextLineSpacePadNum = 0;
+ readyFormattedLine = formattedLine;
+ formattedLine.erase();
+ // queue an empty line prepend request if one exists
+ prependEmptyLine = isPrependPostBlockEmptyLineRequested;
+
+ if (!isSplitLine)
+ {
+ formattedLineCommentNum = string::npos;
+ clearFormattedLineSplitPoints();
+
+ if (isAppendPostBlockEmptyLineRequested)
+ {
+ isAppendPostBlockEmptyLineRequested = false;
+ isPrependPostBlockEmptyLineRequested = true;
+ }
+ else
+ isPrependPostBlockEmptyLineRequested = false;
+ }
+}
+
+/**
+ * check if the currently reached open-brace (i.e. '{')
+ * opens a:
+ * - a definition type block (such as a class or namespace),
+ * - a command block (such as a method block)
+ * - a static array
+ * this method takes for granted that the current character
+ * is an opening brace.
+ *
+ * @return the type of the opened block.
+ */
+BraceType ASFormatter::getBraceType()
+{
+ assert(currentChar == '{');
+
+ BraceType returnVal = NULL_TYPE;
+
+ if ((previousNonWSChar == '='
+ || isBraceType(braceTypeStack->back(), ARRAY_TYPE))
+ && previousCommandChar != ')'
+ && !isNonParenHeader)
+ returnVal = ARRAY_TYPE;
+ else if (foundPreDefinitionHeader && previousCommandChar != ')')
+ {
+ returnVal = DEFINITION_TYPE;
+ if (foundNamespaceHeader)
+ returnVal = (BraceType)(returnVal | NAMESPACE_TYPE);
+ else if (foundClassHeader)
+ returnVal = (BraceType)(returnVal | CLASS_TYPE);
+ else if (foundStructHeader)
+ returnVal = (BraceType)(returnVal | STRUCT_TYPE);
+ else if (foundInterfaceHeader)
+ returnVal = (BraceType)(returnVal | INTERFACE_TYPE);
+ }
+ else if (isInEnum)
+ {
+ returnVal = (BraceType)(ARRAY_TYPE | ENUM_TYPE);
+ }
+ else
+ {
+ bool isCommandType = (foundPreCommandHeader
+ || foundPreCommandMacro
+ || (currentHeader != nullptr && isNonParenHeader)
+ || (previousCommandChar == ')')
+ || (previousCommandChar == ':' && !foundQuestionMark)
+ || (previousCommandChar == ';')
+ || ((previousCommandChar == '{' || previousCommandChar == '}')
+ && isPreviousBraceBlockRelated)
+ || (isInClassInitializer
+ && (!isLegalNameChar(previousNonWSChar) || foundPreCommandHeader))
+ || foundTrailingReturnType
+ || isInObjCMethodDefinition
+ || isInObjCInterface
+ || isJavaStaticConstructor
+ || isSharpDelegate);
+
+ // C# methods containing 'get', 'set', 'add', and 'remove' do NOT end with parens
+ if (!isCommandType && isSharpStyle() && isNextWordSharpNonParenHeader(charNum + 1))
+ {
+ isCommandType = true;
+ isSharpAccessor = true;
+ }
+
+ if (isInExternC)
+ returnVal = (isCommandType ? COMMAND_TYPE : EXTERN_TYPE);
+ else
+ returnVal = (isCommandType ? COMMAND_TYPE : ARRAY_TYPE);
+ }
+
+ int foundOneLineBlock = isOneLineBlockReached(currentLine, charNum);
+
+ if (foundOneLineBlock == 2 && returnVal == COMMAND_TYPE)
+ returnVal = ARRAY_TYPE;
+
+ if (foundOneLineBlock > 0)
+ {
+ returnVal = (BraceType) (returnVal | SINGLE_LINE_TYPE);
+ if (breakCurrentOneLineBlock)
+ returnVal = (BraceType) (returnVal | BREAK_BLOCK_TYPE);
+ if (foundOneLineBlock == 3)
+ returnVal = (BraceType)(returnVal | EMPTY_BLOCK_TYPE);
+ }
+
+ if (isBraceType(returnVal, ARRAY_TYPE))
+ {
+ if (isNonInStatementArrayBrace())
+ {
+ returnVal = (BraceType)(returnVal | ARRAY_NIS_TYPE);
+ isNonInStatementArray = true;
+ isImmediatelyPostNonInStmt = false; // in case of "},{"
+ nonInStatementBrace = formattedLine.length() - 1;
+ }
+ if (isUniformInitializerBrace())
+ returnVal = (BraceType)(returnVal | INIT_TYPE);
+ }
+
+ return returnVal;
+}
+
+/**
+* check if a colon is a class initializer separator
+*
+* @return whether it is a class initializer separator
+*/
+bool ASFormatter::isClassInitializer() const
+{
+ assert(currentChar == ':');
+ assert(previousChar != ':' && peekNextChar() != ':'); // not part of '::'
+
+ // this should be similar to ASBeautifier::parseCurrentLine()
+ bool foundClassInitializer = false;
+
+ if (foundQuestionMark)
+ {
+ // do nothing special
+ }
+ else if (parenStack->back() > 0)
+ {
+ // found a 'for' loop or an objective-C statement
+ // so do nothing special
+ }
+ else if (isInEnum)
+ {
+ // found an enum with a base-type
+ }
+ else if (isCStyle()
+ && !isInCase
+ && (previousCommandChar == ')' || foundPreCommandHeader))
+ {
+ // found a 'class' c'tor initializer
+ foundClassInitializer = true;
+ }
+ return foundClassInitializer;
+}
+
+/**
+ * check if a line is empty
+ *
+ * @return whether line is empty
+ */
+bool ASFormatter::isEmptyLine(const string& line) const
+{
+ return line.find_first_not_of(" \t") == string::npos;
+}
+
+/**
+ * Check if the following text is "C" as in extern "C".
+ *
+ * @return whether the statement is extern "C"
+ */
+bool ASFormatter::isExternC() const
+{
+ // charNum should be at 'extern'
+ assert(!isWhiteSpace(currentLine[charNum]));
+ size_t startQuote = currentLine.find_first_of(" \t\"", charNum);
+ if (startQuote == string::npos)
+ return false;
+ startQuote = currentLine.find_first_not_of(" \t", startQuote);
+ if (startQuote == string::npos)
+ return false;
+ if (currentLine.compare(startQuote, 3, "\"C\"") != 0)
+ return false;
+ return true;
+}
+
+/**
+ * Check if the currently reached '*', '&' or '^' character is
+ * a pointer-or-reference symbol, or another operator.
+ * A pointer dereference (*) or an "address of" character (&)
+ * counts as a pointer or reference because it is not an
+ * arithmetic operator.
+ *
+ * @return whether current character is a reference-or-pointer
+ */
+bool ASFormatter::isPointerOrReference() const
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+
+ if (isJavaStyle())
+ return false;
+
+ if (isCharImmediatelyPostOperator)
+ return false;
+
+ // get the last legal word (may be a number)
+ string lastWord = getPreviousWord(currentLine, charNum);
+ if (lastWord.empty())
+ lastWord = " ";
+
+ // check for preceding or following numeric values
+ string nextText = peekNextText(currentLine.substr(charNum + 1));
+ if (nextText.length() == 0)
+ nextText = " ";
+ char nextChar = nextText[0];
+ if (isDigit(lastWord[0])
+ || isDigit(nextChar)
+ || nextChar == '!'
+ || nextChar == '~')
+ return false;
+
+ // check for multiply then a dereference (a * *b)
+ if (currentChar == '*'
+ && charNum < (int) currentLine.length() - 1
+ && isWhiteSpace(currentLine[charNum + 1])
+ && nextChar == '*')
+ return false;
+
+ if ((foundCastOperator && nextChar == '>')
+ || isPointerOrReferenceVariable(lastWord))
+ return true;
+
+ if (isInClassInitializer
+ && previousNonWSChar != '('
+ && previousNonWSChar != '{'
+ && previousCommandChar != ','
+ && nextChar != ')'
+ && nextChar != '}')
+ return false;
+
+ //check for rvalue reference
+ if (currentChar == '&' && nextChar == '&')
+ {
+ if (previousNonWSChar == '>')
+ return true;
+ string followingText;
+ if ((int) currentLine.length() > charNum + 2)
+ followingText = peekNextText(currentLine.substr(charNum + 2));
+ if (followingText.length() > 0 && followingText[0] == ')')
+ return true;
+ if (currentHeader != nullptr || isInPotentialCalculation)
+ return false;
+ if (parenStack->back() > 0 && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
+ return false;
+ return true;
+ }
+ if (nextChar == '*'
+ || previousNonWSChar == '='
+ || previousNonWSChar == '('
+ || previousNonWSChar == '['
+ || isCharImmediatelyPostReturn
+ || isInTemplate
+ || isCharImmediatelyPostTemplate
+ || currentHeader == &AS_CATCH
+ || currentHeader == &AS_FOREACH
+ || currentHeader == &AS_QFOREACH)
+ return true;
+
+ if (isBraceType(braceTypeStack->back(), ARRAY_TYPE)
+ && isLegalNameChar(lastWord[0])
+ && isLegalNameChar(nextChar)
+ && previousNonWSChar != ')')
+ {
+ if (isArrayOperator())
+ return false;
+ }
+
+ // checks on operators in parens
+ if (parenStack->back() > 0
+ && isLegalNameChar(lastWord[0])
+ && isLegalNameChar(nextChar))
+ {
+ // if followed by an assignment it is a pointer or reference
+ // if followed by semicolon it is a pointer or reference in range-based for
+ const string* followingOperator = getFollowingOperator();
+ if (followingOperator != nullptr
+ && followingOperator != &AS_MULT
+ && followingOperator != &AS_BIT_AND)
+ {
+ if (followingOperator == &AS_ASSIGN || followingOperator == &AS_COLON)
+ return true;
+ return false;
+ }
+
+ if (isBraceType(braceTypeStack->back(), COMMAND_TYPE)
+ || squareBracketCount > 0)
+ return false;
+ return true;
+ }
+
+ // checks on operators in parens with following '('
+ if (parenStack->back() > 0
+ && nextChar == '('
+ && previousNonWSChar != ','
+ && previousNonWSChar != '('
+ && previousNonWSChar != '!'
+ && previousNonWSChar != '&'
+ && previousNonWSChar != '*'
+ && previousNonWSChar != '|')
+ return false;
+
+ if (nextChar == '-'
+ || nextChar == '+')
+ {
+ size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (nextNum != string::npos)
+ {
+ if (currentLine.compare(nextNum, 2, "++") != 0
+ && currentLine.compare(nextNum, 2, "--") != 0)
+ return false;
+ }
+ }
+
+ bool isPR = (!isInPotentialCalculation
+ || (!isLegalNameChar(previousNonWSChar)
+ && !(previousNonWSChar == ')' && nextChar == '(')
+ && !(previousNonWSChar == ')' && currentChar == '*' && !isImmediatelyPostCast())
+ && previousNonWSChar != ']')
+ || (!isWhiteSpace(nextChar)
+ && nextChar != '-'
+ && nextChar != '('
+ && nextChar != '['
+ && !isLegalNameChar(nextChar))
+ );
+
+ return isPR;
+}
+
+/**
+ * Check if the currently reached '*' or '&' character is
+ * a dereferenced pointer or "address of" symbol.
+ * NOTE: this MUST be a pointer or reference as determined by
+ * the function isPointerOrReference().
+ *
+ * @return whether current character is a dereference or address of
+ */
+bool ASFormatter::isDereferenceOrAddressOf() const
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+
+ if (isCharImmediatelyPostTemplate)
+ return false;
+
+ if (previousNonWSChar == '='
+ || previousNonWSChar == ','
+ || previousNonWSChar == '.'
+ || previousNonWSChar == '{'
+ || previousNonWSChar == '>'
+ || previousNonWSChar == '<'
+ || previousNonWSChar == '?'
+ || isCharImmediatelyPostLineComment
+ || isCharImmediatelyPostComment
+ || isCharImmediatelyPostReturn)
+ return true;
+
+ char nextChar = peekNextChar();
+ if (currentChar == '*' && nextChar == '*')
+ {
+ if (previousNonWSChar == '(')
+ return true;
+ if ((int) currentLine.length() < charNum + 2)
+ return true;
+ return false;
+ }
+ if (currentChar == '&' && nextChar == '&')
+ {
+ if (previousNonWSChar == '(' || isInTemplate)
+ return true;
+ if ((int) currentLine.length() < charNum + 2)
+ return true;
+ return false;
+ }
+
+ // check first char on the line
+ if (charNum == (int) currentLine.find_first_not_of(" \t")
+ && (isBraceType(braceTypeStack->back(), COMMAND_TYPE)
+ || parenStack->back() != 0))
+ return true;
+
+ string nextText = peekNextText(currentLine.substr(charNum + 1));
+ if (nextText.length() > 0)
+ {
+ if (nextText[0] == ')' || nextText[0] == '>'
+ || nextText[0] == ',' || nextText[0] == '=')
+ return false;
+ if (nextText[0] == ';')
+ return true;
+ }
+
+ // check for reference to a pointer *& (cannot have &*)
+ if ((currentChar == '*' && nextChar == '&')
+ || (previousNonWSChar == '*' && currentChar == '&'))
+ return false;
+
+ if (!isBraceType(braceTypeStack->back(), COMMAND_TYPE)
+ && parenStack->back() == 0)
+ return false;
+
+ string lastWord = getPreviousWord(currentLine, charNum);
+ if (lastWord == "else" || lastWord == "delete")
+ return true;
+
+ if (isPointerOrReferenceVariable(lastWord))
+ return false;
+
+ bool isDA = (!(isLegalNameChar(previousNonWSChar) || previousNonWSChar == '>')
+ || (nextText.length() > 0 && !isLegalNameChar(nextText[0]) && nextText[0] != '/')
+ || (ispunct((unsigned char)previousNonWSChar) && previousNonWSChar != '.')
+ || isCharImmediatelyPostReturn);
+
+ return isDA;
+}
+
+/**
+ * Check if the currently reached '*' or '&' character is
+ * centered with one space on each side.
+ * Only spaces are checked, not tabs.
+ * If true then a space will be deleted on the output.
+ *
+ * @return whether current character is centered.
+ */
+bool ASFormatter::isPointerOrReferenceCentered() const
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+
+ int prNum = charNum;
+ int lineLength = (int) currentLine.length();
+
+ // check for end of line
+ if (peekNextChar() == ' ')
+ return false;
+
+ // check space before
+ if (prNum < 1
+ || currentLine[prNum - 1] != ' ')
+ return false;
+
+ // check no space before that
+ if (prNum < 2
+ || currentLine[prNum - 2] == ' ')
+ return false;
+
+ // check for ** or &&
+ if (prNum + 1 < lineLength
+ && (currentLine[prNum + 1] == '*' || currentLine[prNum + 1] == '&'))
+ prNum++;
+
+ // check space after
+ if (prNum + 1 <= lineLength
+ && currentLine[prNum + 1] != ' ')
+ return false;
+
+ // check no space after that
+ if (prNum + 2 < lineLength
+ && currentLine[prNum + 2] == ' ')
+ return false;
+
+ return true;
+}
+
+/**
+ * Check if a word is a pointer or reference variable type.
+ *
+ * @return whether word is a pointer or reference variable.
+ */
+bool ASFormatter::isPointerOrReferenceVariable(const string& word) const
+{
+ return (word == "char"
+ || word == "int"
+ || word == "void"
+ || (word.length() >= 6 // check end of word for _t
+ && word.compare(word.length() - 2, 2, "_t") == 0)
+ || word == "INT"
+ || word == "VOID");
+}
+
+/**
+ * check if the currently reached '+' or '-' character is a unary operator
+ * this method takes for granted that the current character
+ * is a '+' or '-'.
+ *
+ * @return whether the current '+' or '-' is a unary operator.
+ */
+bool ASFormatter::isUnaryOperator() const
+{
+ assert(currentChar == '+' || currentChar == '-');
+
+ return ((isCharImmediatelyPostReturn || !isLegalNameChar(previousCommandChar))
+ && previousCommandChar != '.'
+ && previousCommandChar != '\"'
+ && previousCommandChar != '\''
+ && previousCommandChar != ')'
+ && previousCommandChar != ']');
+}
+
+/**
+ * check if the currently reached comment is in a 'switch' statement
+ *
+ * @return whether the current '+' or '-' is in an exponent.
+ */
+bool ASFormatter::isInSwitchStatement() const
+{
+ assert(isInLineComment || isInComment);
+ if (!preBraceHeaderStack->empty())
+ for (size_t i = 1; i < preBraceHeaderStack->size(); i++)
+ if (preBraceHeaderStack->at(i) == &AS_SWITCH)
+ return true;
+ return false;
+}
+
+/**
+ * check if the currently reached '+' or '-' character is
+ * part of an exponent, i.e. 0.2E-5.
+ *
+ * @return whether the current '+' or '-' is in an exponent.
+ */
+bool ASFormatter::isInExponent() const
+{
+ assert(currentChar == '+' || currentChar == '-');
+
+ if (charNum >= 2)
+ {
+ char prevPrevFormattedChar = currentLine[charNum - 2];
+ char prevFormattedChar = currentLine[charNum - 1];
+ return ((prevFormattedChar == 'e' || prevFormattedChar == 'E')
+ && (prevPrevFormattedChar == '.' || isDigit(prevPrevFormattedChar)));
+ }
+ return false;
+}
+
+/**
+ * check if an array brace should NOT have an in-statement indent
+ *
+ * @return the array is non in-statement
+ */
+bool ASFormatter::isNonInStatementArrayBrace() const
+{
+ bool returnVal = false;
+ char nextChar = peekNextChar();
+ // if this opening brace begins the line there will be no inStatement indent
+ if (currentLineBeginsWithBrace
+ && charNum == (int) currentLineFirstBraceNum
+ && nextChar != '}')
+ returnVal = true;
+ // if an opening brace ends the line there will be no inStatement indent
+ if (isWhiteSpace(nextChar)
+ || isBeforeAnyLineEndComment(charNum)
+ || nextChar == '{')
+ returnVal = true;
+
+ // Java "new Type [] {...}" IS an inStatement indent
+ if (isJavaStyle() && previousNonWSChar == ']')
+ returnVal = false;
+
+ return returnVal;
+}
+
+/**
+ * check if a one-line block has been reached,
+ * i.e. if the currently reached '{' character is closed
+ * with a complimentary '}' elsewhere on the current line,
+ *.
+ * @return 0 = one-line block has not been reached.
+ * 1 = one-line block has been reached.
+ * 2 = one-line block has been reached and is followed by a comma.
+ * 3 = one-line block has been reached and is an empty block.
+ */
+int ASFormatter::isOneLineBlockReached(const string& line, int startChar) const
+{
+ assert(line[startChar] == '{');
+
+ bool isInComment_ = false;
+ bool isInQuote_ = false;
+ bool hasText = false;
+ int braceCount = 0;
+ int lineLength = line.length();
+ char quoteChar_ = ' ';
+ char ch = ' ';
+ char prevCh = ' ';
+
+ for (int i = startChar; i < lineLength; ++i)
+ {
+ 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 == '\'' && !isDigitSeparator(line, i)))
+ {
+ isInQuote_ = true;
+ quoteChar_ = ch;
+ continue;
+ }
+
+ if (line.compare(i, 2, "//") == 0)
+ break;
+
+ if (line.compare(i, 2, "/*") == 0)
+ {
+ isInComment_ = true;
+ ++i;
+ continue;
+ }
+
+ if (ch == '{')
+ {
+ ++braceCount;
+ continue;
+ }
+ if (ch == '}')
+ {
+ --braceCount;
+ if (braceCount == 0)
+ {
+ // is this an array?
+ if (parenStack->back() == 0 && prevCh != '}')
+ {
+ size_t peekNum = line.find_first_not_of(" \t", i + 1);
+ if (peekNum != string::npos && line[peekNum] == ',')
+ return 2;
+ }
+ if (!hasText)
+ return 3; // is an empty block
+ return 1;
+ }
+ }
+ if (ch == ';')
+ continue;
+ if (!isWhiteSpace(ch))
+ {
+ hasText = true;
+ prevCh = ch;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * peek at the next word to determine if it is a C# non-paren header.
+ * will look ahead in the input file if necessary.
+ *
+ * @param startChar position on currentLine to start the search
+ * @return true if the next word is get or set.
+ */
+bool ASFormatter::isNextWordSharpNonParenHeader(int startChar) const
+{
+ // look ahead to find the next non-comment text
+ string nextText = peekNextText(currentLine.substr(startChar));
+ if (nextText.length() == 0)
+ return false;
+ if (nextText[0] == '[')
+ return true;
+ if (!isCharPotentialHeader(nextText, 0))
+ return false;
+ if (findKeyword(nextText, 0, AS_GET) || findKeyword(nextText, 0, AS_SET)
+ || findKeyword(nextText, 0, AS_ADD) || findKeyword(nextText, 0, AS_REMOVE))
+ return true;
+ return false;
+}
+
+/**
+ * peek at the next char to determine if it is an opening brace.
+ * will look ahead in the input file if necessary.
+ * this determines a java static constructor.
+ *
+ * @param startChar position on currentLine to start the search
+ * @return true if the next word is an opening brace.
+ */
+bool ASFormatter::isNextCharOpeningBrace(int startChar) const
+{
+ bool retVal = false;
+ string nextText = peekNextText(currentLine.substr(startChar));
+ if (nextText.length() > 0
+ && nextText.compare(0, 1, "{") == 0)
+ retVal = true;
+ return retVal;
+}
+
+/**
+* Check if operator and, pointer, and reference padding is disabled.
+* Disabling is done thru a NOPAD tag in an ending comment.
+*
+* @return true if the formatting on this line is disabled.
+*/
+bool ASFormatter::isOperatorPaddingDisabled() const
+{
+ size_t commentStart = currentLine.find("//", charNum);
+ if (commentStart == string::npos)
+ {
+ commentStart = currentLine.find("/*", charNum);
+ // comment must end on this line
+ if (commentStart != string::npos)
+ {
+ size_t commentEnd = currentLine.find("*/", commentStart + 2);
+ if (commentEnd == string::npos)
+ commentStart = string::npos;
+ }
+ }
+ if (commentStart == string::npos)
+ return false;
+ size_t noPadStart = currentLine.find("*NOPAD*", commentStart);
+ if (noPadStart == string::npos)
+ return false;
+ return true;
+}
+
+/**
+* Determine if an opening array-type brace should have a leading space pad.
+* This is to identify C++11 uniform initializers.
+*/
+bool ASFormatter::isUniformInitializerBrace() const
+{
+ if (isCStyle() && !isInEnum && !isImmediatelyPostPreprocessor)
+ {
+ if (isInClassInitializer
+ || isLegalNameChar(previousNonWSChar))
+ return true;
+ }
+ return false;
+}
+
+/**
+* Determine if there is a following statement on the current line.
+*/
+bool ASFormatter::isMultiStatementLine() const
+{
+ assert((isImmediatelyPostHeader || foundClosingHeader));
+ bool isInComment_ = false;
+ bool isInQuote_ = false;
+ int semiCount_ = 0;
+ int parenCount_ = 0;
+ int braceCount_ = 0;
+
+ for (size_t i = 0; i < currentLine.length(); i++)
+ {
+ if (isInComment_)
+ {
+ if (currentLine.compare(i, 2, "*/") == 0)
+ {
+ isInComment_ = false;
+ continue;
+ }
+ }
+ if (currentLine.compare(i, 2, "/*") == 0)
+ {
+ isInComment_ = true;
+ continue;
+ }
+ if (currentLine.compare(i, 2, "//") == 0)
+ return false;
+ if (isInQuote_)
+ {
+ if (currentLine[i] == '"' || currentLine[i] == '\'')
+ isInQuote_ = false;
+ continue;
+ }
+ if (currentLine[i] == '"' || currentLine[i] == '\'')
+ {
+ isInQuote_ = true;
+ continue;
+ }
+ if (currentLine[i] == '(')
+ {
+ ++parenCount_;
+ continue;
+ }
+ if (currentLine[i] == ')')
+ {
+ --parenCount_;
+ continue;
+ }
+ if (parenCount_ > 0)
+ continue;
+ if (currentLine[i] == '{')
+ {
+ ++braceCount_;
+ }
+ if (currentLine[i] == '}')
+ {
+ --braceCount_;
+ }
+ if (braceCount_ > 0)
+ continue;
+ if (currentLine[i] == ';')
+ {
+ ++semiCount_;
+ if (semiCount_ > 1)
+ return true;
+ continue;
+ }
+ }
+ return false;
+}
+
+/**
+ * get the next non-whitespace substring on following lines, bypassing all comments.
+ *
+ * @param firstLine the first line to check
+ * @return the next non-whitespace substring.
+ */
+string ASFormatter::peekNextText(const string& firstLine,
+ bool endOnEmptyLine /*false*/,
+ shared_ptr<ASPeekStream> streamArg /*nullptr*/) const
+{
+ bool isFirstLine = true;
+ string nextLine_ = firstLine;
+ size_t firstChar = string::npos;
+ shared_ptr<ASPeekStream> stream = streamArg;
+ if (stream == nullptr) // Borland may need == 0
+ stream = make_shared<ASPeekStream>(sourceIterator);
+
+ // find the first non-blank text, bypassing all comments.
+ bool isInComment_ = false;
+ while (stream->hasMoreLines() || isFirstLine)
+ {
+ if (isFirstLine)
+ isFirstLine = false;
+ else
+ nextLine_ = stream->peekNextLine();
+
+ firstChar = nextLine_.find_first_not_of(" \t");
+ if (firstChar == string::npos)
+ {
+ if (endOnEmptyLine && !isInComment_)
+ break;
+ continue;
+ }
+
+ if (nextLine_.compare(firstChar, 2, "/*") == 0)
+ {
+ firstChar += 2;
+ isInComment_ = true;
+ }
+
+ if (isInComment_)
+ {
+ firstChar = nextLine_.find("*/", firstChar);
+ if (firstChar == string::npos)
+ continue;
+ firstChar += 2;
+ isInComment_ = false;
+ firstChar = nextLine_.find_first_not_of(" \t", firstChar);
+ if (firstChar == string::npos)
+ continue;
+ }
+
+ if (nextLine_.compare(firstChar, 2, "//") == 0)
+ continue;
+
+ // found the next text
+ break;
+ }
+
+ if (firstChar == string::npos)
+ nextLine_ = "";
+ else
+ nextLine_ = nextLine_.substr(firstChar);
+ return nextLine_;
+}
+
+/**
+ * adjust comment position because of adding or deleting spaces
+ * the spaces are added or deleted to formattedLine
+ * spacePadNum contains the adjustment
+ */
+void ASFormatter::adjustComments()
+{
+ assert(spacePadNum != 0);
+ assert(isSequenceReached("//") || isSequenceReached("/*"));
+
+ // block comment must be closed on this line with nothing after it
+ if (isSequenceReached("/*"))
+ {
+ size_t endNum = currentLine.find("*/", charNum + 2);
+ if (endNum == string::npos)
+ return;
+ if (currentLine.find_first_not_of(" \t", endNum + 2) != string::npos)
+ return;
+ }
+
+ size_t len = formattedLine.length();
+ // don't adjust a tab
+ if (formattedLine[len - 1] == '\t')
+ return;
+ // if spaces were removed, need to add spaces before the comment
+ if (spacePadNum < 0)
+ {
+ int adjust = -spacePadNum; // make the number positive
+ formattedLine.append(adjust, ' ');
+ }
+ // if spaces were added, need to delete extra spaces before the comment
+ // if cannot be done put the comment one space after the last text
+ else if (spacePadNum > 0)
+ {
+ int adjust = spacePadNum;
+ size_t lastText = formattedLine.find_last_not_of(' ');
+ if (lastText != string::npos
+ && lastText < len - adjust - 1)
+ formattedLine.resize(len - adjust);
+ else if (len > lastText + 2)
+ formattedLine.resize(lastText + 2);
+ else if (len < lastText + 2)
+ formattedLine.append(len - lastText, ' ');
+ }
+}
+
+/**
+ * append the current brace inside the end of line comments
+ * currentChar contains the brace, it will be appended to formattedLine
+ * formattedLineCommentNum is the comment location on formattedLine
+ */
+void ASFormatter::appendCharInsideComments()
+{
+ if (formattedLineCommentNum == string::npos // does the comment start on the previous line?
+ || formattedLineCommentNum == 0)
+ {
+ appendCurrentChar(); // don't attach
+ return;
+ }
+ assert(formattedLine.compare(formattedLineCommentNum, 2, "//") == 0
+ || formattedLine.compare(formattedLineCommentNum, 2, "/*") == 0);
+
+ // find the previous non space char
+ size_t end = formattedLineCommentNum;
+ size_t beg = formattedLine.find_last_not_of(" \t", end - 1);
+ if (beg == string::npos)
+ {
+ appendCurrentChar(); // don't attach
+ return;
+ }
+ beg++;
+
+ // insert the brace
+ if (end - beg < 3) // is there room to insert?
+ formattedLine.insert(beg, 3 - end + beg, ' ');
+ if (formattedLine[beg] == '\t') // don't pad with a tab
+ formattedLine.insert(beg, 1, ' ');
+ formattedLine[beg + 1] = currentChar;
+ testForTimeToSplitFormattedLine();
+
+ if (isBeforeComment())
+ breakLine();
+ else if (isCharImmediatelyPostLineComment)
+ shouldBreakLineAtNextChar = true;
+}
+
+/**
+ * add or remove space padding to operators
+ * the operators and necessary padding will be appended to formattedLine
+ * the calling function should have a continue statement after calling this method
+ *
+ * @param newOperator the operator to be padded
+ */
+void ASFormatter::padOperators(const string* newOperator)
+{
+ assert(shouldPadOperators);
+ assert(newOperator != nullptr);
+
+ char nextNonWSChar = ASBase::peekNextChar(currentLine, charNum);
+ bool shouldPad = (newOperator != &AS_SCOPE_RESOLUTION
+ && newOperator != &AS_PLUS_PLUS
+ && newOperator != &AS_MINUS_MINUS
+ && newOperator != &AS_NOT
+ && newOperator != &AS_BIT_NOT
+ && newOperator != &AS_ARROW
+ && !(newOperator == &AS_COLON && !foundQuestionMark // objC methods
+ && (isInObjCMethodDefinition || isInObjCInterface
+ || isInObjCSelector || squareBracketCount != 0))
+ && !(newOperator == &AS_MINUS && isInExponent())
+ && !(newOperator == &AS_PLUS && isInExponent())
+ && !((newOperator == &AS_PLUS || newOperator == &AS_MINUS) // check for unary plus or minus
+ && (previousNonWSChar == '('
+ || previousNonWSChar == '['
+ || previousNonWSChar == '='
+ || previousNonWSChar == ','
+ || previousNonWSChar == ':'
+ || previousNonWSChar == '{'))
+//? // commented out in release 2.05.1 - doesn't seem to do anything???
+//x && !((newOperator == &AS_MULT || newOperator == &AS_BIT_AND || newOperator == &AS_AND)
+//x && isPointerOrReference())
+ && !(newOperator == &AS_MULT
+ && (previousNonWSChar == '.'
+ || previousNonWSChar == '>')) // check for ->
+ && !(newOperator == &AS_MULT && peekNextChar() == '>')
+ && !((isInTemplate || isImmediatelyPostTemplate)
+ && (newOperator == &AS_LS || newOperator == &AS_GR))
+ && !(newOperator == &AS_GCC_MIN_ASSIGN
+ && ASBase::peekNextChar(currentLine, charNum + 1) == '>')
+ && !(newOperator == &AS_GR && previousNonWSChar == '?')
+ && !(newOperator == &AS_QUESTION // check for Java wildcard
+ && isJavaStyle()
+ && (previousNonWSChar == '<'
+ || nextNonWSChar == '>'
+ || nextNonWSChar == '.'))
+ && !(newOperator == &AS_QUESTION // check for C# null conditional operator
+ && isSharpStyle()
+ && (nextNonWSChar == '.'
+ || nextNonWSChar == '['))
+ && !isCharImmediatelyPostOperator
+ && !isInCase
+ && !isInAsm
+ && !isInAsmOneLine
+ && !isInAsmBlock
+ );
+
+ // pad before operator
+ if (shouldPad
+ && !(newOperator == &AS_COLON
+ && (!foundQuestionMark && !isInEnum) && currentHeader != &AS_FOR)
+ && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
+ && currentLine.find(':', charNum + 1) == string::npos)
+ )
+ appendSpacePad();
+ appendOperator(*newOperator);
+ goForward(newOperator->length() - 1);
+
+ currentChar = (*newOperator)[newOperator->length() - 1];
+ // pad after operator
+ // but do not pad after a '-' that is a unary-minus.
+ if (shouldPad
+ && !isBeforeAnyComment()
+ && !(newOperator == &AS_PLUS && isUnaryOperator())
+ && !(newOperator == &AS_MINUS && isUnaryOperator())
+ && !(currentLine.compare(charNum + 1, 1, AS_SEMICOLON) == 0)
+ && !(currentLine.compare(charNum + 1, 2, AS_SCOPE_RESOLUTION) == 0)
+ && !(peekNextChar() == ',')
+ && !(newOperator == &AS_QUESTION && isSharpStyle() // check for C# nullable type (e.g. int?)
+ && peekNextChar() == '[')
+ )
+ appendSpaceAfter();
+}
+
+/**
+ * format pointer or reference
+ * currentChar contains the pointer or reference
+ * the symbol and necessary padding will be appended to formattedLine
+ * the calling function should have a continue statement after calling this method
+ *
+ * NOTE: Do NOT use appendCurrentChar() in this method. The line should not be
+ * broken once the calculation starts.
+ */
+void ASFormatter::formatPointerOrReference()
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+ assert(!isJavaStyle());
+
+ int pa = pointerAlignment;
+ int ra = referenceAlignment;
+ int itemAlignment = (currentChar == '*' || currentChar == '^') ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
+
+ // check for ** and &&
+ int ptrLength = 1;
+ char peekedChar = peekNextChar();
+ if ((currentChar == '*' && peekedChar == '*')
+ || (currentChar == '&' && peekedChar == '&'))
+ {
+ ptrLength = 2;
+ size_t nextChar = currentLine.find_first_not_of(" \t", charNum + 2);
+ if (nextChar == string::npos)
+ peekedChar = ' ';
+ else
+ peekedChar = currentLine[nextChar];
+ }
+ // check for cast
+ if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',')
+ {
+ formatPointerOrReferenceCast();
+ return;
+ }
+
+ // check for a padded space and remove it
+ if (charNum > 0
+ && !isWhiteSpace(currentLine[charNum - 1])
+ && formattedLine.length() > 0
+ && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
+ {
+ formattedLine.erase(formattedLine.length() - 1);
+ spacePadNum--;
+ }
+
+ if (itemAlignment == PTR_ALIGN_TYPE)
+ {
+ formatPointerOrReferenceToType();
+ }
+ else if (itemAlignment == PTR_ALIGN_MIDDLE)
+ {
+ formatPointerOrReferenceToMiddle();
+ }
+ else if (itemAlignment == PTR_ALIGN_NAME)
+ {
+ formatPointerOrReferenceToName();
+ }
+ else // pointerAlignment == PTR_ALIGN_NONE
+ {
+ formattedLine.append(ptrLength, currentChar);
+ if (ptrLength > 1)
+ goForward(ptrLength - 1);
+ }
+}
+
+/**
+ * format pointer or reference with align to type
+ */
+void ASFormatter::formatPointerOrReferenceToType()
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+ assert(!isJavaStyle());
+
+ // do this before bumping charNum
+ bool isOldPRCentered = isPointerOrReferenceCentered();
+
+ size_t prevCh = formattedLine.find_last_not_of(" \t");
+ if (prevCh == string::npos)
+ prevCh = 0;
+ if (formattedLine.length() == 0 || prevCh == formattedLine.length() - 1)
+ formattedLine.append(1, currentChar);
+ else
+ {
+ // exchange * or & with character following the type
+ // this may not work every time with a tab character
+ string charSave = formattedLine.substr(prevCh + 1, 1);
+ formattedLine[prevCh + 1] = currentChar;
+ formattedLine.append(charSave);
+ }
+ if (isSequenceReached("**") || isSequenceReached("&&"))
+ {
+ if (formattedLine.length() == 1)
+ formattedLine.append(1, currentChar);
+ else
+ formattedLine.insert(prevCh + 2, 1, currentChar);
+ goForward(1);
+ }
+ // if no space after then add one
+ if (charNum < (int) currentLine.length() - 1
+ && !isWhiteSpace(currentLine[charNum + 1])
+ && currentLine[charNum + 1] != ')')
+ appendSpacePad();
+ // if old pointer or reference is centered, remove a space
+ if (isOldPRCentered
+ && isWhiteSpace(formattedLine[formattedLine.length() - 1]))
+ {
+ formattedLine.erase(formattedLine.length() - 1, 1);
+ spacePadNum--;
+ }
+ // update the formattedLine split point
+ if (maxCodeLength != string::npos)
+ {
+ size_t index = formattedLine.length() - 1;
+ if (isWhiteSpace(formattedLine[index]))
+ {
+ updateFormattedLineSplitPointsPointerOrReference(index);
+ testForTimeToSplitFormattedLine();
+ }
+ }
+}
+
+/**
+ * format pointer or reference with align in the middle
+ */
+void ASFormatter::formatPointerOrReferenceToMiddle()
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+ assert(!isJavaStyle());
+
+ // compute current whitespace before
+ size_t wsBefore = currentLine.find_last_not_of(" \t", charNum - 1);
+ if (wsBefore == string::npos)
+ wsBefore = 0;
+ else
+ wsBefore = charNum - wsBefore - 1;
+ string sequenceToInsert(1, currentChar);
+ if (isSequenceReached("**"))
+ {
+ sequenceToInsert = "**";
+ goForward(1);
+ }
+ else if (isSequenceReached("&&"))
+ {
+ sequenceToInsert = "&&";
+ goForward(1);
+ }
+ // if reference to a pointer check for conflicting alignment
+ else if (currentChar == '*' && peekNextChar() == '&'
+ && (referenceAlignment == REF_ALIGN_TYPE
+ || referenceAlignment == REF_ALIGN_MIDDLE
+ || referenceAlignment == REF_SAME_AS_PTR))
+ {
+ sequenceToInsert = "*&";
+ goForward(1);
+ for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++)
+ goForward(1);
+ }
+ // if a comment follows don't align, just space pad
+ if (isBeforeAnyComment())
+ {
+ appendSpacePad();
+ formattedLine.append(sequenceToInsert);
+ appendSpaceAfter();
+ return;
+ }
+ // do this before goForward()
+ bool isAfterScopeResolution = previousNonWSChar == ':';
+ size_t charNumSave = charNum;
+ // if this is the last thing on the line
+ if (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos)
+ {
+ if (wsBefore == 0 && !isAfterScopeResolution)
+ formattedLine.append(1, ' ');
+ formattedLine.append(sequenceToInsert);
+ return;
+ }
+ // goForward() to convert tabs to spaces, if necessary,
+ // and move following characters to preceding characters
+ // this may not work every time with tab characters
+ for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
+ {
+ goForward(1);
+ if (formattedLine.length() > 0)
+ formattedLine.append(1, currentLine[i]);
+ else
+ spacePadNum--;
+ }
+ // find space padding after
+ size_t wsAfter = currentLine.find_first_not_of(" \t", charNumSave + 1);
+ if (wsAfter == string::npos || isBeforeAnyComment())
+ wsAfter = 0;
+ else
+ wsAfter = wsAfter - charNumSave - 1;
+ // don't pad before scope resolution operator, but pad after
+ if (isAfterScopeResolution)
+ {
+ size_t lastText = formattedLine.find_last_not_of(" \t");
+ formattedLine.insert(lastText + 1, sequenceToInsert);
+ appendSpacePad();
+ }
+ else if (formattedLine.length() > 0)
+ {
+ // whitespace should be at least 2 chars to center
+ if (wsBefore + wsAfter < 2)
+ {
+ size_t charsToAppend = (2 - (wsBefore + wsAfter));
+ formattedLine.append(charsToAppend, ' ');
+ spacePadNum += charsToAppend;
+ if (wsBefore == 0)
+ wsBefore++;
+ if (wsAfter == 0)
+ wsAfter++;
+ }
+ // insert the pointer or reference char
+ size_t padAfter = (wsBefore + wsAfter) / 2;
+ size_t index = formattedLine.length() - padAfter;
+ formattedLine.insert(index, sequenceToInsert);
+ }
+ else // formattedLine.length() == 0
+ {
+ formattedLine.append(sequenceToInsert);
+ if (wsAfter == 0)
+ wsAfter++;
+ formattedLine.append(wsAfter, ' ');
+ spacePadNum += wsAfter;
+ }
+ // update the formattedLine split point after the pointer
+ if (maxCodeLength != string::npos && formattedLine.length() > 0)
+ {
+ size_t index = formattedLine.find_last_not_of(" \t");
+ if (index != string::npos && (index < formattedLine.length() - 1))
+ {
+ index++;
+ updateFormattedLineSplitPointsPointerOrReference(index);
+ testForTimeToSplitFormattedLine();
+ }
+ }
+}
+
+/**
+ * format pointer or reference with align to name
+ */
+void ASFormatter::formatPointerOrReferenceToName()
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+ assert(!isJavaStyle());
+
+ // do this before bumping charNum
+ bool isOldPRCentered = isPointerOrReferenceCentered();
+
+ size_t startNum = formattedLine.find_last_not_of(" \t");
+ if (startNum == string::npos)
+ startNum = 0;
+ string sequenceToInsert(1, currentChar);
+ if (isSequenceReached("**"))
+ {
+ sequenceToInsert = "**";
+ goForward(1);
+ }
+ else if (isSequenceReached("&&"))
+ {
+ sequenceToInsert = "&&";
+ goForward(1);
+ }
+ // if reference to a pointer align both to name
+ else if (currentChar == '*' && peekNextChar() == '&')
+ {
+ sequenceToInsert = "*&";
+ goForward(1);
+ for (size_t i = charNum; i < currentLine.length() - 1 && isWhiteSpace(currentLine[i]); i++)
+ goForward(1);
+ }
+ char peekedChar = peekNextChar();
+ bool isAfterScopeResolution = previousNonWSChar == ':'; // check for ::
+ // if this is not the last thing on the line
+ if (!isBeforeAnyComment()
+ && (int) currentLine.find_first_not_of(" \t", charNum + 1) > charNum)
+ {
+ // goForward() to convert tabs to spaces, if necessary,
+ // and move following characters to preceding characters
+ // this may not work every time with tab characters
+ for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
+ {
+ // if a padded paren follows don't move
+ if (shouldPadParensOutside && peekedChar == '(' && !isOldPRCentered)
+ {
+ // empty parens don't count
+ size_t start = currentLine.find_first_not_of("( \t", charNum + 1);
+ if (start != string::npos && currentLine[start] != ')')
+ break;
+ }
+ goForward(1);
+ if (formattedLine.length() > 0)
+ formattedLine.append(1, currentLine[i]);
+ else
+ spacePadNum--;
+ }
+ }
+ // don't pad before scope resolution operator
+ if (isAfterScopeResolution)
+ {
+ size_t lastText = formattedLine.find_last_not_of(" \t");
+ if (lastText != string::npos && lastText + 1 < formattedLine.length())
+ formattedLine.erase(lastText + 1);
+ }
+ // if no space before * then add one
+ else if (formattedLine.length() > 0
+ && (formattedLine.length() <= startNum + 1
+ || !isWhiteSpace(formattedLine[startNum + 1])))
+ {
+ formattedLine.insert(startNum + 1, 1, ' ');
+ spacePadNum++;
+ }
+ appendSequence(sequenceToInsert, false);
+ // if old pointer or reference is centered, remove a space
+ if (isOldPRCentered
+ && formattedLine.length() > startNum + 1
+ && isWhiteSpace(formattedLine[startNum + 1])
+ && !isBeforeAnyComment())
+ {
+ formattedLine.erase(startNum + 1, 1);
+ spacePadNum--;
+ }
+ // don't convert to *= or &=
+ if (peekedChar == '=')
+ {
+ appendSpaceAfter();
+ // if more than one space before, delete one
+ if (formattedLine.length() > startNum
+ && isWhiteSpace(formattedLine[startNum + 1])
+ && isWhiteSpace(formattedLine[startNum + 2]))
+ {
+ formattedLine.erase(startNum + 1, 1);
+ spacePadNum--;
+ }
+ }
+ // update the formattedLine split point
+ if (maxCodeLength != string::npos)
+ {
+ size_t index = formattedLine.find_last_of(" \t");
+ if (index != string::npos
+ && index < formattedLine.length() - 1
+ && (formattedLine[index + 1] == '*'
+ || formattedLine[index + 1] == '&'
+ || formattedLine[index + 1] == '^'))
+ {
+ updateFormattedLineSplitPointsPointerOrReference(index);
+ testForTimeToSplitFormattedLine();
+ }
+ }
+}
+
+/**
+ * format pointer or reference cast
+ * currentChar contains the pointer or reference
+ * NOTE: the pointers and references in function definitions
+ * are processed as a cast (e.g. void foo(void*, void*))
+ * is processed here.
+ */
+void ASFormatter::formatPointerOrReferenceCast()
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+ assert(!isJavaStyle());
+
+ int pa = pointerAlignment;
+ int ra = referenceAlignment;
+ int itemAlignment = (currentChar == '*' || currentChar == '^') ? pa : ((ra == REF_SAME_AS_PTR) ? pa : ra);
+
+ string sequenceToInsert(1, currentChar);
+ if (isSequenceReached("**") || isSequenceReached("&&"))
+ {
+ goForward(1);
+ sequenceToInsert.append(1, currentLine[charNum]);
+ }
+ if (itemAlignment == PTR_ALIGN_NONE)
+ {
+ appendSequence(sequenceToInsert, false);
+ return;
+ }
+ // remove preceding whitespace
+ char prevCh = ' ';
+ size_t prevNum = formattedLine.find_last_not_of(" \t");
+ if (prevNum != string::npos)
+ {
+ prevCh = formattedLine[prevNum];
+ if (prevNum + 1 < formattedLine.length()
+ && isWhiteSpace(formattedLine[prevNum + 1])
+ && prevCh != '(')
+ {
+ spacePadNum -= (formattedLine.length() - 1 - prevNum);
+ formattedLine.erase(prevNum + 1);
+ }
+ }
+ bool isAfterScopeResolution = previousNonWSChar == ':';
+ if ((itemAlignment == PTR_ALIGN_MIDDLE || itemAlignment == PTR_ALIGN_NAME)
+ && !isAfterScopeResolution && prevCh != '(')
+ {
+ appendSpacePad();
+ // in this case appendSpacePad may or may not update the split point
+ if (maxCodeLength != string::npos && formattedLine.length() > 0)
+ updateFormattedLineSplitPointsPointerOrReference(formattedLine.length() - 1);
+ appendSequence(sequenceToInsert, false);
+ }
+ else
+ appendSequence(sequenceToInsert, false);
+}
+
+/**
+ * add or remove space padding to parens
+ * currentChar contains the paren
+ * the parens and necessary padding will be appended to formattedLine
+ * the calling function should have a continue statement after calling this method
+ */
+void ASFormatter::padParens()
+{
+ assert(currentChar == '(' || currentChar == ')');
+ assert(shouldPadParensOutside || shouldPadParensInside || shouldUnPadParens || shouldPadFirstParen);
+
+ int spacesOutsideToDelete = 0;
+ int spacesInsideToDelete = 0;
+
+ if (currentChar == '(')
+ {
+ spacesOutsideToDelete = formattedLine.length() - 1;
+ spacesInsideToDelete = 0;
+
+ // compute spaces outside the opening paren to delete
+ if (shouldUnPadParens)
+ {
+ char lastChar = ' ';
+ bool prevIsParenHeader = false;
+ size_t i = formattedLine.find_last_not_of(" \t");
+ if (i != string::npos)
+ {
+ // if last char is a brace the previous whitespace is an indent
+ if (formattedLine[i] == '{')
+ spacesOutsideToDelete = 0;
+ else if (isCharImmediatelyPostPointerOrReference)
+ spacesOutsideToDelete = 0;
+ else
+ {
+ spacesOutsideToDelete -= i;
+ lastChar = formattedLine[i];
+ // if previous word is a header, it will be a paren header
+ string prevWord = getPreviousWord(formattedLine, formattedLine.length());
+ const string* prevWordH = nullptr;
+ if (shouldPadHeader
+ && prevWord.length() > 0
+ && isCharPotentialHeader(prevWord, 0))
+ prevWordH = ASBase::findHeader(prevWord, 0, headers);
+ if (prevWordH != nullptr)
+ prevIsParenHeader = true;
+ else if (prevWord == AS_RETURN) // don't unpad
+ prevIsParenHeader = true;
+ else if ((prevWord == AS_NEW || prevWord == AS_DELETE)
+ && shouldPadHeader) // don't unpad
+ prevIsParenHeader = true;
+ else if (isCStyle() && prevWord == AS_THROW && shouldPadHeader) // don't unpad
+ prevIsParenHeader = true;
+ else if (prevWord == "and" || prevWord == "or" || prevWord == "in") // don't unpad
+ prevIsParenHeader = true;
+ // don't unpad variables
+ else if (prevWord == "bool"
+ || prevWord == "int"
+ || prevWord == "void"
+ || prevWord == "void*"
+ || prevWord == "char"
+ || prevWord == "char*"
+ || prevWord == "long"
+ || prevWord == "double"
+ || prevWord == "float"
+ || (prevWord.length() >= 4 // check end of word for _t
+ && prevWord.compare(prevWord.length() - 2, 2, "_t") == 0)
+ || prevWord == "Int32"
+ || prevWord == "UInt32"
+ || prevWord == "Int64"
+ || prevWord == "UInt64"
+ || prevWord == "BOOL"
+ || prevWord == "DWORD"
+ || prevWord == "HWND"
+ || prevWord == "INT"
+ || prevWord == "LPSTR"
+ || prevWord == "VOID"
+ || prevWord == "LPVOID"
+ )
+ {
+ prevIsParenHeader = true;
+ }
+ }
+ }
+ // do not unpad operators, but leave them if already padded
+ if (shouldPadParensOutside || prevIsParenHeader)
+ spacesOutsideToDelete--;
+ else if (lastChar == '|' // check for ||
+ || lastChar == '&' // check for &&
+ || lastChar == ','
+ || (lastChar == '(' && shouldPadParensInside)
+ || (lastChar == '>' && !foundCastOperator)
+ || lastChar == '<'
+ || lastChar == '?'
+ || lastChar == ':'
+ || lastChar == ';'
+ || lastChar == '='
+ || lastChar == '+'
+ || lastChar == '-'
+ || lastChar == '*'
+ || lastChar == '/'
+ || lastChar == '%'
+ || lastChar == '^'
+ )
+ spacesOutsideToDelete--;
+
+ if (spacesOutsideToDelete > 0)
+ {
+ formattedLine.erase(i + 1, spacesOutsideToDelete);
+ spacePadNum -= spacesOutsideToDelete;
+ }
+ }
+
+ // pad open paren outside
+ char peekedCharOutside = peekNextChar();
+ if (shouldPadFirstParen && previousChar != '(' && peekedCharOutside != ')')
+ appendSpacePad();
+ else if (shouldPadParensOutside)
+ {
+ if (!(currentChar == '(' && peekedCharOutside == ')'))
+ appendSpacePad();
+ }
+
+ appendCurrentChar();
+
+ // unpad open paren inside
+ if (shouldUnPadParens)
+ {
+ size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (j != string::npos)
+ spacesInsideToDelete = j - charNum - 1;
+ if (shouldPadParensInside)
+ spacesInsideToDelete--;
+ if (spacesInsideToDelete > 0)
+ {
+ currentLine.erase(charNum + 1, spacesInsideToDelete);
+ spacePadNum -= spacesInsideToDelete;
+ }
+ // convert tab to space if requested
+ if (shouldConvertTabs
+ && (int) currentLine.length() > charNum + 1
+ && currentLine[charNum + 1] == '\t')
+ currentLine[charNum + 1] = ' ';
+ }
+
+ // pad open paren inside
+ char peekedCharInside = peekNextChar();
+ if (shouldPadParensInside)
+ if (!(currentChar == '(' && peekedCharInside == ')'))
+ appendSpaceAfter();
+ }
+ else if (currentChar == ')')
+ {
+ // unpad close paren inside
+ if (shouldUnPadParens)
+ {
+ spacesInsideToDelete = formattedLine.length();
+ size_t i = formattedLine.find_last_not_of(" \t");
+ if (i != string::npos)
+ spacesInsideToDelete = formattedLine.length() - 1 - i;
+ if (shouldPadParensInside)
+ spacesInsideToDelete--;
+ if (spacesInsideToDelete > 0)
+ {
+ formattedLine.erase(i + 1, spacesInsideToDelete);
+ spacePadNum -= spacesInsideToDelete;
+ }
+ }
+
+ // pad close paren inside
+ if (shouldPadParensInside)
+ if (!(previousChar == '(' && currentChar == ')'))
+ appendSpacePad();
+
+ appendCurrentChar();
+
+ // unpad close paren outside
+ // close parens outside are left unchanged
+ if (shouldUnPadParens)
+ {
+ //spacesOutsideToDelete = 0;
+ //size_t j = currentLine.find_first_not_of(" \t", charNum + 1);
+ //if (j != string::npos)
+ // spacesOutsideToDelete = j - charNum - 1;
+ //if (shouldPadParensOutside)
+ // spacesOutsideToDelete--;
+
+ //if (spacesOutsideToDelete > 0)
+ //{
+ // currentLine.erase(charNum + 1, spacesOutsideToDelete);
+ // spacePadNum -= spacesOutsideToDelete;
+ //}
+ }
+
+ // pad close paren outside
+ char peekedCharOutside = peekNextChar();
+ if (shouldPadParensOutside)
+ if (peekedCharOutside != ';'
+ && peekedCharOutside != ','
+ && peekedCharOutside != '.'
+ && peekedCharOutside != '+' // check for ++
+ && peekedCharOutside != '-' // check for --
+ && peekedCharOutside != ']')
+ appendSpaceAfter();
+ }
+}
+
+/**
+* add or remove space padding to objective-c parens
+* these options have precedence over the padParens methods
+* the padParens method has already been called, this method adjusts
+*/
+void ASFormatter::padObjCMethodPrefix()
+{
+ assert(currentChar == '(' && isImmediatelyPostObjCMethodPrefix);
+ assert(shouldPadMethodPrefix || shouldUnPadMethodPrefix);
+
+ size_t prefix = formattedLine.find_first_of("+-");
+ if (prefix == string::npos)
+ return;
+ size_t paren = formattedLine.find_first_of('(');
+ if (paren == string::npos)
+ return;
+ int spaces = paren - prefix - 1;
+
+ if (shouldPadMethodPrefix)
+ {
+ if (spaces == 0)
+ {
+ formattedLine.insert(prefix + 1, 1, ' ');
+ spacePadNum += 1;
+ }
+ else if (spaces > 1)
+ {
+ formattedLine.erase(prefix + 1, spaces - 1);
+ spacePadNum -= spaces - 1;
+ }
+ }
+ // this option will be ignored if used with pad-method-prefix
+ else if (shouldUnPadMethodPrefix)
+ {
+ if (spaces > 0)
+ {
+ formattedLine.erase(prefix + 1, spaces);
+ spacePadNum -= spaces;
+ }
+ }
+}
+
+/**
+* add or remove space padding to objective-c parens
+* these options have precedence over the padParens methods
+* the padParens method has already been called, this method adjusts
+*/
+void ASFormatter::padObjCReturnType()
+{
+ assert(currentChar == ')' && isInObjCReturnType);
+ assert(shouldPadReturnType || shouldUnPadReturnType);
+
+ size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (nextText == string::npos)
+ return;
+ int spaces = nextText - charNum - 1;
+
+ if (shouldPadReturnType)
+ {
+ if (spaces == 0)
+ {
+ // this will already be padded if pad-paren is used
+ if (formattedLine[formattedLine.length() - 1] != ' ')
+ {
+ formattedLine.append(" ");
+ spacePadNum += 1;
+ }
+ }
+ else if (spaces > 1)
+ {
+ // do not use goForward here
+ currentLine.erase(charNum + 1, spaces - 1);
+ spacePadNum -= spaces - 1;
+ }
+ }
+ // this option will be ignored if used with pad-return-type
+ else if (shouldUnPadReturnType)
+ {
+ // this will already be padded if pad-paren is used
+ if (formattedLine[formattedLine.length() - 1] == ' ')
+ {
+ spacePadNum -= formattedLine.length() - 1 - nextText;
+ int lastText = formattedLine.find_last_not_of(" \t");
+ formattedLine.resize(lastText + 1);
+ }
+ if (spaces > 0)
+ {
+ // do not use goForward here
+ currentLine.erase(charNum + 1, spaces);
+ spacePadNum -= spaces;
+ }
+ }
+}
+
+/**
+* add or remove space padding to objective-c parens
+* these options have precedence over the padParens methods
+* the padParens method has already been called, this method adjusts
+*/
+void ASFormatter::padObjCParamType()
+{
+ assert((currentChar == '(' || currentChar == ')') && isInObjCMethodDefinition);
+ assert(!isImmediatelyPostObjCMethodPrefix && !isInObjCReturnType);
+ assert(shouldPadParamType || shouldUnPadParamType);
+
+ if (currentChar == '(')
+ {
+ // open paren has already been attached to formattedLine by padParen
+ size_t paramOpen = formattedLine.rfind('(');
+ assert(paramOpen != string::npos);
+ size_t prevText = formattedLine.find_last_not_of(" \t", paramOpen - 1);
+ if (prevText == string::npos)
+ return;
+ int spaces = paramOpen - prevText - 1;
+
+ if (shouldPadParamType
+ || objCColonPadMode == COLON_PAD_ALL
+ || objCColonPadMode == COLON_PAD_AFTER)
+ {
+ if (spaces == 0)
+ {
+ formattedLine.insert(paramOpen, 1, ' ');
+ spacePadNum += 1;
+ }
+ if (spaces > 1)
+ {
+ formattedLine.erase(prevText + 1, spaces - 1);
+ spacePadNum -= spaces - 1;
+ }
+ }
+ // this option will be ignored if used with pad-param-type
+ else if (shouldUnPadParamType
+ || objCColonPadMode == COLON_PAD_NONE
+ || objCColonPadMode == COLON_PAD_BEFORE)
+ {
+ if (spaces > 0)
+ {
+ formattedLine.erase(prevText + 1, spaces);
+ spacePadNum -= spaces;
+ }
+ }
+ }
+ else if (currentChar == ')')
+ {
+ size_t nextText = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (nextText == string::npos)
+ return;
+ int spaces = nextText - charNum - 1;
+
+ if (shouldPadParamType)
+ {
+ if (spaces == 0)
+ {
+ // this will already be padded if pad-paren is used
+ if (formattedLine[formattedLine.length() - 1] != ' ')
+ {
+ formattedLine.append(" ");
+ spacePadNum += 1;
+ }
+ }
+ else if (spaces > 1)
+ {
+ // do not use goForward here
+ currentLine.erase(charNum + 1, spaces - 1);
+ spacePadNum -= spaces - 1;
+ }
+ }
+ // this option will be ignored if used with pad-param-type
+ else if (shouldUnPadParamType)
+ {
+ // this will already be padded if pad-paren is used
+ if (formattedLine[formattedLine.length() - 1] == ' ')
+ {
+ spacePadNum -= 1;
+ int lastText = formattedLine.find_last_not_of(" \t");
+ formattedLine.resize(lastText + 1);
+ }
+ if (spaces > 0)
+ {
+ // do not use goForward here
+ currentLine.erase(charNum + 1, spaces);
+ spacePadNum -= spaces;
+ }
+ }
+ }
+}
+
+/**
+ * format opening brace as attached or broken
+ * currentChar contains the brace
+ * the braces will be appended to the current formattedLine or a new formattedLine as necessary
+ * the calling function should have a continue statement after calling this method
+ *
+ * @param braceType the type of brace to be formatted.
+ */
+void ASFormatter::formatOpeningBrace(BraceType braceType)
+{
+ assert(!isBraceType(braceType, ARRAY_TYPE));
+ assert(currentChar == '{');
+
+ parenStack->emplace_back(0);
+
+ bool breakBrace = isCurrentBraceBroken();
+
+ if (breakBrace)
+ {
+ if (isBeforeAnyComment() && isOkToBreakBlock(braceType))
+ {
+ // if comment is at line end leave the comment on this line
+ if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
+ {
+ currentChar = ' '; // remove brace from current line
+ if (parenStack->size() > 1)
+ parenStack->pop_back();
+ currentLine[charNum] = currentChar;
+ appendOpeningBrace = true; // append brace to following line
+ }
+ // else put comment after the brace
+ else if (!isBeforeMultipleLineEndComments(charNum))
+ breakLine();
+ }
+ else if (!isBraceType(braceType, SINGLE_LINE_TYPE))
+ {
+ formattedLine = rtrim(formattedLine);
+ breakLine();
+ }
+ else if ((shouldBreakOneLineBlocks || isBraceType(braceType, BREAK_BLOCK_TYPE))
+ && !isBraceType(braceType, EMPTY_BLOCK_TYPE))
+ breakLine();
+ else if (!isInLineBreak)
+ appendSpacePad();
+
+ appendCurrentChar();
+
+ // should a following comment break from the brace?
+ // must break the line AFTER the brace
+ if (isBeforeComment()
+ && formattedLine.length() > 0
+ && formattedLine[0] == '{'
+ && isOkToBreakBlock(braceType)
+ && (braceFormatMode == BREAK_MODE
+ || braceFormatMode == LINUX_MODE))
+ {
+ shouldBreakLineAtNextChar = true;
+ }
+ }
+ else // attach brace
+ {
+ // are there comments before the brace?
+ if (isCharImmediatelyPostComment || isCharImmediatelyPostLineComment)
+ {
+ if (isOkToBreakBlock(braceType)
+ && !(isCharImmediatelyPostComment && isCharImmediatelyPostLineComment) // don't attach if two comments on the line
+ && !isImmediatelyPostPreprocessor
+// && peekNextChar() != '}' // don't attach { } // removed release 2.03
+ && previousCommandChar != '{' // don't attach { {
+ && previousCommandChar != '}' // don't attach } {
+ && previousCommandChar != ';') // don't attach ; {
+ {
+ appendCharInsideComments();
+ }
+ else
+ {
+ appendCurrentChar(); // don't attach
+ }
+ }
+ else if (previousCommandChar == '{'
+ || (previousCommandChar == '}' && !isInClassInitializer)
+ || previousCommandChar == ';') // '}' , ';' chars added for proper handling of '{' immediately after a '}' or ';'
+ {
+ appendCurrentChar(); // don't attach
+ }
+ else
+ {
+ // if a blank line precedes this don't attach
+ if (isEmptyLine(formattedLine))
+ appendCurrentChar(); // don't attach
+ else if (isOkToBreakBlock(braceType)
+ && !(isImmediatelyPostPreprocessor
+ && currentLineBeginsWithBrace))
+ {
+ if (!isBraceType(braceType, EMPTY_BLOCK_TYPE))
+ {
+ appendSpacePad();
+ appendCurrentChar(false); // OK to attach
+ testForTimeToSplitFormattedLine(); // line length will have changed
+ // should a following comment attach with the brace?
+ // insert spaces to reposition the comment
+ if (isBeforeComment()
+ && !isBeforeMultipleLineEndComments(charNum)
+ && (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace))
+ {
+ shouldBreakLineAtNextChar = true;
+ currentLine.insert(charNum + 1, charNum + 1, ' ');
+ }
+ else if (!isBeforeAnyComment()) // added in release 2.03
+ {
+ shouldBreakLineAtNextChar = true;
+ }
+ }
+ else
+ {
+ if (currentLineBeginsWithBrace && charNum == (int) currentLineFirstBraceNum)
+ {
+ appendSpacePad();
+ appendCurrentChar(false); // attach
+ shouldBreakLineAtNextChar = true;
+ }
+ else
+ {
+ appendSpacePad();
+ appendCurrentChar(); // don't attach
+ }
+ }
+ }
+ else
+ {
+ if (!isInLineBreak)
+ appendSpacePad();
+ appendCurrentChar(); // don't attach
+ }
+ }
+ }
+}
+
+/**
+ * format closing brace
+ * currentChar contains the brace
+ * the calling function should have a continue statement after calling this method
+ *
+ * @param braceType the type of the opening brace for this closing brace.
+ */
+void ASFormatter::formatClosingBrace(BraceType braceType)
+{
+ assert(!isBraceType(braceType, ARRAY_TYPE));
+ assert(currentChar == '}');
+
+ // parenStack must contain one entry
+ if (parenStack->size() > 1)
+ parenStack->pop_back();
+
+ // mark state of immediately after empty block
+ // this state will be used for locating braces that appear immediately AFTER an empty block (e.g. '{} \n}').
+ if (previousCommandChar == '{')
+ isImmediatelyPostEmptyBlock = true;
+
+ if (attachClosingBraceMode)
+ {
+ // for now, namespaces and classes will be attached. Uncomment the lines below to break.
+ if ((isEmptyLine(formattedLine) // if a blank line precedes this
+ || isCharImmediatelyPostLineComment
+ || isCharImmediatelyPostComment
+ || (isImmediatelyPostPreprocessor && (int) currentLine.find_first_not_of(" \t") == charNum)
+// || (isBraceType(braceType, CLASS_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{')
+// || (isBraceType(braceType, NAMESPACE_TYPE) && isOkToBreakBlock(braceType) && previousNonWSChar != '{')
+ )
+ && (!isBraceType(braceType, SINGLE_LINE_TYPE) || isOkToBreakBlock(braceType)))
+ {
+ breakLine();
+ appendCurrentChar(); // don't attach
+ }
+ else
+ {
+ if (previousNonWSChar != '{'
+ && (!isBraceType(braceType, SINGLE_LINE_TYPE)
+ || isOkToBreakBlock(braceType)))
+ appendSpacePad();
+ appendCurrentChar(false); // attach
+ }
+ }
+ else if (!isBraceType(braceType, EMPTY_BLOCK_TYPE)
+ && (isBraceType(braceType, BREAK_BLOCK_TYPE)
+ || isOkToBreakBlock(braceType)))
+ {
+ breakLine();
+ appendCurrentChar();
+ }
+ else
+ {
+ appendCurrentChar();
+ }
+
+ // if a declaration follows a definition, space pad
+ if (isLegalNameChar(peekNextChar()))
+ appendSpaceAfter();
+
+ if (shouldBreakBlocks
+ && currentHeader != nullptr
+ && !isHeaderInMultiStatementLine
+ && parenStack->back() == 0)
+ {
+ if (currentHeader == &AS_CASE || currentHeader == &AS_DEFAULT)
+ {
+ // do not yet insert a line if "break" statement is outside the braces
+ string nextText = peekNextText(currentLine.substr(charNum + 1));
+ if (nextText.length() > 0
+ && nextText.substr(0, 5) != "break")
+ isAppendPostBlockEmptyLineRequested = true;
+ }
+ else
+ isAppendPostBlockEmptyLineRequested = true;
+ }
+}
+
+/**
+ * format array braces as attached or broken
+ * determine if the braces can have an inStatement indent
+ * currentChar contains the brace
+ * the braces will be appended to the current formattedLine or a new formattedLine as necessary
+ * the calling function should have a continue statement after calling this method
+ *
+ * @param braceType the type of brace to be formatted, must be an ARRAY_TYPE.
+ * @param isOpeningArrayBrace indicates if this is the opening brace for the array block.
+ */
+void ASFormatter::formatArrayBraces(BraceType braceType, bool isOpeningArrayBrace)
+{
+ assert(isBraceType(braceType, ARRAY_TYPE));
+ assert(currentChar == '{' || currentChar == '}');
+
+ if (currentChar == '{')
+ {
+ // is this the first opening brace in the array?
+ if (isOpeningArrayBrace)
+ {
+ if (braceFormatMode == ATTACH_MODE
+ || braceFormatMode == LINUX_MODE)
+ {
+ // break an enum if mozilla
+ if (isBraceType(braceType, ENUM_TYPE)
+ && formattingStyle == STYLE_MOZILLA)
+ {
+ isInLineBreak = true;
+ appendCurrentChar(); // don't attach
+ }
+ // don't attach to a preprocessor directive or '\' line
+ else if ((isImmediatelyPostPreprocessor
+ || (formattedLine.length() > 0
+ && formattedLine[formattedLine.length() - 1] == '\\'))
+ && currentLineBeginsWithBrace)
+ {
+ isInLineBreak = true;
+ appendCurrentChar(); // don't attach
+ }
+ else if (isCharImmediatelyPostComment)
+ {
+ // TODO: attach brace to line-end comment
+ appendCurrentChar(); // don't attach
+ }
+ else if (isCharImmediatelyPostLineComment && !isBraceType(braceType, SINGLE_LINE_TYPE))
+ {
+ appendCharInsideComments();
+ }
+ else
+ {
+ // if a blank line precedes this don't attach
+ if (isEmptyLine(formattedLine))
+ appendCurrentChar(); // don't attach
+ else
+ {
+ // if brace is broken or not an assignment
+ if (currentLineBeginsWithBrace
+ && !isBraceType(braceType, SINGLE_LINE_TYPE))
+ {
+ appendSpacePad();
+ appendCurrentChar(false); // OK to attach
+ // TODO: debug the following line
+ testForTimeToSplitFormattedLine(); // line length will have changed
+
+ if (currentLineBeginsWithBrace
+ && (int) currentLineFirstBraceNum == charNum)
+ shouldBreakLineAtNextChar = true;
+ }
+ else
+ {
+ if (previousNonWSChar != '(')
+ {
+ // don't space pad C++11 uniform initialization
+ if (!isBraceType(braceType, INIT_TYPE))
+ appendSpacePad();
+ }
+ appendCurrentChar();
+ }
+ }
+ }
+ }
+ else if (braceFormatMode == BREAK_MODE)
+ {
+ if (isWhiteSpace(peekNextChar()) && !isInVirginLine)
+ breakLine();
+ else if (isBeforeAnyComment())
+ {
+ // do not break unless comment is at line end
+ if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
+ {
+ currentChar = ' '; // remove brace from current line
+ appendOpeningBrace = true; // append brace to following line
+ }
+ }
+ if (!isInLineBreak && previousNonWSChar != '(')
+ {
+ // don't space pad C++11 uniform initialization
+ if (!isBraceType(braceType, INIT_TYPE))
+ appendSpacePad();
+ }
+ appendCurrentChar();
+
+ if (currentLineBeginsWithBrace
+ && (int) currentLineFirstBraceNum == charNum
+ && !isBraceType(braceType, SINGLE_LINE_TYPE))
+ shouldBreakLineAtNextChar = true;
+ }
+ else if (braceFormatMode == RUN_IN_MODE)
+ {
+ if (isWhiteSpace(peekNextChar()) && !isInVirginLine)
+ breakLine();
+ else if (isBeforeAnyComment())
+ {
+ // do not break unless comment is at line end
+ if (isBeforeAnyLineEndComment(charNum) && !currentLineBeginsWithBrace)
+ {
+ currentChar = ' '; // remove brace from current line
+ appendOpeningBrace = true; // append brace to following line
+ }
+ }
+ if (!isInLineBreak && previousNonWSChar != '(')
+ {
+ // don't space pad C++11 uniform initialization
+ if (!isBraceType(braceType, INIT_TYPE))
+ appendSpacePad();
+ }
+ appendCurrentChar();
+ }
+ else if (braceFormatMode == NONE_MODE)
+ {
+ if (currentLineBeginsWithBrace
+ && charNum == (int) currentLineFirstBraceNum)
+ {
+ appendCurrentChar(); // don't attach
+ }
+ else
+ {
+ if (previousNonWSChar != '(')
+ {
+ // don't space pad C++11 uniform initialization
+ if (!isBraceType(braceType, INIT_TYPE))
+ appendSpacePad();
+ }
+ appendCurrentChar(false); // OK to attach
+ }
+ }
+ }
+ else // not the first opening brace
+ {
+ if (braceFormatMode == RUN_IN_MODE)
+ {
+ if (previousNonWSChar == '{'
+ && braceTypeStack->size() > 2
+ && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],
+ SINGLE_LINE_TYPE))
+ formatArrayRunIn();
+ }
+ else if (!isInLineBreak
+ && !isWhiteSpace(peekNextChar())
+ && previousNonWSChar == '{'
+ && braceTypeStack->size() > 2
+ && !isBraceType((*braceTypeStack)[braceTypeStack->size() - 2],
+ SINGLE_LINE_TYPE))
+ formatArrayRunIn();
+
+ appendCurrentChar();
+ }
+ }
+ else if (currentChar == '}')
+ {
+ if (attachClosingBraceMode)
+ {
+ if (isEmptyLine(formattedLine) // if a blank line precedes this
+ || isImmediatelyPostPreprocessor
+ || isCharImmediatelyPostLineComment
+ || isCharImmediatelyPostComment)
+ appendCurrentChar(); // don't attach
+ else
+ {
+ appendSpacePad();
+ appendCurrentChar(false); // attach
+ }
+ }
+ else
+ {
+ // does this close the first opening brace in the array?
+ // must check if the block is still a single line because of anonymous statements
+ if (!isBraceType(braceType, INIT_TYPE)
+ && (!isBraceType(braceType, SINGLE_LINE_TYPE)
+ || formattedLine.find('{') == string::npos))
+ breakLine();
+ appendCurrentChar();
+ }
+
+ // if a declaration follows an enum definition, space pad
+ char peekedChar = peekNextChar();
+ if (isLegalNameChar(peekedChar)
+ || peekedChar == '[')
+ appendSpaceAfter();
+ }
+}
+
+/**
+ * determine if a run-in can be attached.
+ * if it can insert the indents in formattedLine and reset the current line break.
+ */
+void ASFormatter::formatRunIn()
+{
+ assert(braceFormatMode == RUN_IN_MODE || braceFormatMode == NONE_MODE);
+
+ // keep one line blocks returns true without indenting the run-in
+ if (formattingStyle != STYLE_PICO
+ && !isOkToBreakBlock(braceTypeStack->back()))
+ return; // true;
+
+ // make sure the line begins with a brace
+ size_t lastText = formattedLine.find_last_not_of(" \t");
+ if (lastText == string::npos || formattedLine[lastText] != '{')
+ return; // false;
+
+ // make sure the brace is broken
+ if (formattedLine.find_first_not_of(" \t{") != string::npos)
+ return; // false;
+
+ if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
+ return; // false;
+
+ bool extraIndent = false;
+ bool extraHalfIndent = false;
+ isInLineBreak = true;
+
+ // cannot attach a class modifier without indent-classes
+ if (isCStyle()
+ && isCharPotentialHeader(currentLine, charNum)
+ && (isBraceType(braceTypeStack->back(), CLASS_TYPE)
+ || (isBraceType(braceTypeStack->back(), STRUCT_TYPE)
+ && isInIndentableStruct)))
+ {
+ if (findKeyword(currentLine, charNum, AS_PUBLIC)
+ || findKeyword(currentLine, charNum, AS_PRIVATE)
+ || findKeyword(currentLine, charNum, AS_PROTECTED))
+ {
+ if (getModifierIndent())
+ extraHalfIndent = true;
+ else if (!getClassIndent())
+ return; // false;
+ }
+ else if (getClassIndent())
+ extraIndent = true;
+ }
+
+ // cannot attach a 'case' statement without indent-switches
+ if (!getSwitchIndent()
+ && isCharPotentialHeader(currentLine, charNum)
+ && (findKeyword(currentLine, charNum, AS_CASE)
+ || findKeyword(currentLine, charNum, AS_DEFAULT)))
+ return; // false;
+
+ // extra indent for switch statements
+ if (getSwitchIndent()
+ && !preBraceHeaderStack->empty()
+ && preBraceHeaderStack->back() == &AS_SWITCH
+ && ((isLegalNameChar(currentChar)
+ && !findKeyword(currentLine, charNum, AS_CASE))))
+ extraIndent = true;
+
+ isInLineBreak = false;
+ // remove for extra whitespace
+ if (formattedLine.length() > lastText + 1
+ && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos)
+ formattedLine.erase(lastText + 1);
+
+ if (extraHalfIndent)
+ {
+ int indentLength_ = getIndentLength();
+ runInIndentChars = indentLength_ / 2;
+ formattedLine.append(runInIndentChars - 1, ' ');
+ }
+ else if (getForceTabIndentation() && getIndentLength() != getTabLength())
+ {
+ // insert the space indents
+ string indent;
+ int indentLength_ = getIndentLength();
+ int tabLength_ = getTabLength();
+ indent.append(indentLength_, ' ');
+ if (extraIndent)
+ indent.append(indentLength_, ' ');
+ // replace spaces indents with tab indents
+ size_t tabCount = indent.length() / tabLength_; // truncate extra spaces
+ indent.replace(0U, tabCount * tabLength_, tabCount, '\t');
+ runInIndentChars = indentLength_;
+ if (indent[0] == ' ') // allow for brace
+ indent.erase(0, 1);
+ formattedLine.append(indent);
+ }
+ else if (getIndentString() == "\t")
+ {
+ appendChar('\t', false);
+ runInIndentChars = 2; // one for { and one for tab
+ if (extraIndent)
+ {
+ appendChar('\t', false);
+ runInIndentChars++;
+ }
+ }
+ else // spaces
+ {
+ int indentLength_ = getIndentLength();
+ formattedLine.append(indentLength_ - 1, ' ');
+ runInIndentChars = indentLength_;
+ if (extraIndent)
+ {
+ formattedLine.append(indentLength_, ' ');
+ runInIndentChars += indentLength_;
+ }
+ }
+ isInBraceRunIn = true;
+}
+
+/**
+ * remove whitespace and add indentation for an array run-in.
+ */
+void ASFormatter::formatArrayRunIn()
+{
+ assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));
+
+ // make sure the brace is broken
+ if (formattedLine.find_first_not_of(" \t{") != string::npos)
+ return;
+
+ size_t lastText = formattedLine.find_last_not_of(" \t");
+ if (lastText == string::npos || formattedLine[lastText] != '{')
+ return;
+
+ // check for extra whitespace
+ if (formattedLine.length() > lastText + 1
+ && formattedLine.find_first_not_of(" \t", lastText + 1) == string::npos)
+ formattedLine.erase(lastText + 1);
+
+ if (getIndentString() == "\t")
+ {
+ appendChar('\t', false);
+ runInIndentChars = 2; // one for { and one for tab
+ }
+ else
+ {
+ int indent = getIndentLength();
+ formattedLine.append(indent - 1, ' ');
+ runInIndentChars = indent;
+ }
+ isInBraceRunIn = true;
+ isInLineBreak = false;
+}
+
+/**
+ * delete a braceTypeStack vector object
+ * BraceTypeStack did not work with the DeleteContainer template
+ */
+void ASFormatter::deleteContainer(vector<BraceType>*& container)
+{
+ if (container != nullptr)
+ {
+ container->clear();
+ delete (container);
+ container = nullptr;
+ }
+}
+
+/**
+ * delete a vector object
+ * T is the type of vector
+ * used for all vectors except braceTypeStack
+ */
+template<typename T>
+void ASFormatter::deleteContainer(T& container)
+{
+ if (container != nullptr)
+ {
+ container->clear();
+ delete (container);
+ container = nullptr;
+ }
+}
+
+/**
+ * initialize a braceType vector object
+ * braceType did not work with the DeleteContainer template
+ */
+void ASFormatter::initContainer(vector<BraceType>*& container, vector<BraceType>* value)
+{
+ if (container != nullptr)
+ deleteContainer(container);
+ container = value;
+}
+
+/**
+ * initialize a vector object
+ * T is the type of vector
+ * used for all vectors except braceTypeStack
+ */
+template<typename T>
+void ASFormatter::initContainer(T& container, T value)
+{
+ // since the ASFormatter object is never deleted,
+ // the existing vectors must be deleted before creating new ones
+ if (container != nullptr)
+ deleteContainer(container);
+ container = value;
+}
+
+/**
+ * convert a tab to spaces.
+ * charNum points to the current 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.
+ * replaces the tab in currentLine with the required number of spaces.
+ * replaces the value of currentChar.
+ */
+void ASFormatter::convertTabToSpaces()
+{
+ assert(currentChar == '\t');
+
+ // do NOT replace if in quotes
+ if (isInQuote || isInQuoteContinuation)
+ return;
+
+ size_t tabSize = getTabLength();
+ size_t numSpaces = tabSize - ((tabIncrementIn + charNum) % tabSize);
+ currentLine.replace(charNum, 1, numSpaces, ' ');
+ currentChar = currentLine[charNum];
+}
+
+/**
+* is it ok to break this block?
+*/
+bool ASFormatter::isOkToBreakBlock(BraceType braceType) const
+{
+ // Actually, there should not be an ARRAY_TYPE brace here.
+ // But this will avoid breaking a one line block when there is.
+ // Otherwise they will be formatted differently on consecutive runs.
+ if (isBraceType(braceType, ARRAY_TYPE)
+ && isBraceType(braceType, SINGLE_LINE_TYPE))
+ return false;
+ if (isBraceType(braceType, COMMAND_TYPE)
+ && isBraceType(braceType, EMPTY_BLOCK_TYPE))
+ return false;
+ if (!isBraceType(braceType, SINGLE_LINE_TYPE)
+ || isBraceType(braceType, BREAK_BLOCK_TYPE)
+ || shouldBreakOneLineBlocks)
+ return true;
+ return false;
+}
+
+/**
+* check if a sharp header is a paren or non-paren header
+*/
+bool ASFormatter::isSharpStyleWithParen(const string* header) const
+{
+ return (isSharpStyle() && peekNextChar() == '('
+ && (header == &AS_CATCH
+ || header == &AS_DELEGATE));
+}
+
+/**
+ * Check for a following header when a comment is reached.
+ * firstLine must contain the start of the comment.
+ * return value is a pointer to the header or nullptr.
+ */
+const string* ASFormatter::checkForHeaderFollowingComment(const string& firstLine) const
+{
+ assert(isInComment || isInLineComment);
+ assert(shouldBreakElseIfs || shouldBreakBlocks || isInSwitchStatement());
+ // look ahead to find the next non-comment text
+ bool endOnEmptyLine = (currentHeader == nullptr);
+ if (isInSwitchStatement())
+ endOnEmptyLine = false;
+ string nextText = peekNextText(firstLine, endOnEmptyLine);
+
+ if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
+ return nullptr;
+
+ return ASBase::findHeader(nextText, 0, headers);
+}
+
+/**
+ * process preprocessor statements.
+ * charNum should be the index of the #.
+ *
+ * delete braceTypeStack entries added by #if if a #else is found.
+ * prevents double entries in the braceTypeStack.
+ */
+void ASFormatter::processPreprocessor()
+{
+ assert(currentChar == '#');
+
+ const size_t preproc = currentLine.find_first_not_of(" \t", charNum + 1);
+
+ if (preproc == string::npos)
+ return;
+
+ if (currentLine.compare(preproc, 2, "if") == 0)
+ {
+ preprocBraceTypeStackSize = braceTypeStack->size();
+ }
+ else if (currentLine.compare(preproc, 4, "else") == 0)
+ {
+ // delete stack entries added in #if
+ // should be replaced by #else
+ if (preprocBraceTypeStackSize > 0)
+ {
+ int addedPreproc = braceTypeStack->size() - preprocBraceTypeStackSize;
+ for (int i = 0; i < addedPreproc; i++)
+ braceTypeStack->pop_back();
+ }
+ }
+}
+
+/**
+ * determine if the next line starts a comment
+ * and a header follows the comment or comments.
+ */
+bool ASFormatter::commentAndHeaderFollows()
+{
+ // called ONLY IF shouldDeleteEmptyLines and shouldBreakBlocks are TRUE.
+ assert(shouldDeleteEmptyLines && shouldBreakBlocks);
+
+ // is the next line a comment
+ auto stream = make_shared<ASPeekStream>(sourceIterator);
+ if (!stream->hasMoreLines())
+ return false;
+ string nextLine_ = stream->peekNextLine();
+ size_t firstChar = nextLine_.find_first_not_of(" \t");
+ if (firstChar == string::npos
+ || !(nextLine_.compare(firstChar, 2, "//") == 0
+ || nextLine_.compare(firstChar, 2, "/*") == 0))
+ return false;
+
+ // find the next non-comment text, and reset
+ string nextText = peekNextText(nextLine_, false, stream);
+ if (nextText.length() == 0 || !isCharPotentialHeader(nextText, 0))
+ return false;
+
+ const string* newHeader = ASBase::findHeader(nextText, 0, headers);
+
+ if (newHeader == nullptr)
+ return false;
+
+ // if a closing header, reset break unless break is requested
+ if (isClosingHeader(newHeader) && !shouldBreakClosingHeaderBlocks)
+ {
+ isAppendPostBlockEmptyLineRequested = false;
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * determine if a brace should be attached or broken
+ * uses braces in the braceTypeStack
+ * the last brace in the braceTypeStack is the one being formatted
+ * returns true if the brace should be broken
+ */
+bool ASFormatter::isCurrentBraceBroken() const
+{
+ assert(braceTypeStack->size() > 1);
+
+ bool breakBrace = false;
+ size_t stackEnd = braceTypeStack->size() - 1;
+
+ // check brace modifiers
+ if (shouldAttachExternC
+ && isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))
+ {
+ return false;
+ }
+ if (shouldAttachNamespace
+ && isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))
+ {
+ return false;
+ }
+ if (shouldAttachClass
+ && (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)
+ || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE)))
+ {
+ return false;
+ }
+ if (shouldAttachInline
+ && isCStyle() // for C++ only
+ && braceFormatMode != RUN_IN_MODE
+ && !(currentLineBeginsWithBrace && peekNextChar() == '/')
+ && isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))
+ {
+ size_t i;
+ for (i = 1; i < braceTypeStack->size(); i++)
+ if (isBraceType((*braceTypeStack)[i], CLASS_TYPE)
+ || isBraceType((*braceTypeStack)[i], STRUCT_TYPE))
+ return false;
+ }
+
+ // check braces
+ if (isBraceType((*braceTypeStack)[stackEnd], EXTERN_TYPE))
+ {
+ if (currentLineBeginsWithBrace
+ || braceFormatMode == RUN_IN_MODE)
+ breakBrace = true;
+ }
+ else if (braceFormatMode == NONE_MODE)
+ {
+ if (currentLineBeginsWithBrace
+ && (int) currentLineFirstBraceNum == charNum)
+ breakBrace = true;
+ }
+ else if (braceFormatMode == BREAK_MODE || braceFormatMode == RUN_IN_MODE)
+ {
+ breakBrace = true;
+ }
+ else if (braceFormatMode == LINUX_MODE)
+ {
+ // break a namespace if NOT stroustrup or mozilla
+ if (isBraceType((*braceTypeStack)[stackEnd], NAMESPACE_TYPE))
+ {
+ if (formattingStyle != STYLE_STROUSTRUP
+ && formattingStyle != STYLE_MOZILLA)
+ breakBrace = true;
+ }
+ // break a class or interface if NOT stroustrup
+ else if (isBraceType((*braceTypeStack)[stackEnd], CLASS_TYPE)
+ || isBraceType((*braceTypeStack)[stackEnd], INTERFACE_TYPE))
+ {
+ if (formattingStyle != STYLE_STROUSTRUP)
+ breakBrace = true;
+ }
+ // break a struct if mozilla - an enum is processed as an array brace
+ else if (isBraceType((*braceTypeStack)[stackEnd], STRUCT_TYPE))
+ {
+ if (formattingStyle == STYLE_MOZILLA)
+ breakBrace = true;
+ }
+ // break the first brace if a function
+ else if (isBraceType((*braceTypeStack)[stackEnd], COMMAND_TYPE))
+ {
+ if (stackEnd == 1)
+ {
+ breakBrace = true;
+ }
+ else if (stackEnd > 1)
+ {
+ // break the first brace after these if a function
+ if (isBraceType((*braceTypeStack)[stackEnd - 1], NAMESPACE_TYPE)
+ || isBraceType((*braceTypeStack)[stackEnd - 1], CLASS_TYPE)
+ || isBraceType((*braceTypeStack)[stackEnd - 1], ARRAY_TYPE)
+ || isBraceType((*braceTypeStack)[stackEnd - 1], STRUCT_TYPE)
+ || isBraceType((*braceTypeStack)[stackEnd - 1], EXTERN_TYPE))
+ {
+ breakBrace = true;
+ }
+ }
+ }
+ }
+ return breakBrace;
+}
+
+/**
+ * format comment body
+ * the calling function should have a continue statement after calling this method
+ */
+void ASFormatter::formatCommentBody()
+{
+ assert(isInComment);
+
+ // append the comment
+ while (charNum < (int) currentLine.length())
+ {
+ currentChar = currentLine[charNum];
+ if (isSequenceReached("*/"))
+ {
+ formatCommentCloser();
+ break;
+ }
+ if (currentChar == '\t' && shouldConvertTabs)
+ convertTabToSpaces();
+ appendCurrentChar();
+ ++charNum;
+ }
+ if (shouldStripCommentPrefix)
+ stripCommentPrefix();
+}
+
+/**
+ * format a comment opener
+ * the comment opener will be appended to the current formattedLine or a new formattedLine as necessary
+ * the calling function should have a continue statement after calling this method
+ */
+void ASFormatter::formatCommentOpener()
+{
+ assert(isSequenceReached("/*"));
+
+ isInComment = isInCommentStartLine = true;
+ isImmediatelyPostLineComment = false;
+ if (previousNonWSChar == '}')
+ resetEndOfStatement();
+
+ // Check for a following header.
+ // For speed do not check multiple comment lines more than once.
+ // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.
+ const string* followingHeader = nullptr;
+ if ((doesLineStartComment
+ && !isImmediatelyPostCommentOnly
+ && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
+ && (shouldBreakElseIfs
+ || isInSwitchStatement()
+ || (shouldBreakBlocks
+ && !isImmediatelyPostEmptyLine
+ && previousCommandChar != '{')))
+ followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));
+
+ if (spacePadNum != 0 && !isInLineBreak)
+ adjustComments();
+ formattedLineCommentNum = formattedLine.length();
+
+ // must be done BEFORE appendSequence
+ if (previousCommandChar == '{'
+ && !isImmediatelyPostComment
+ && !isImmediatelyPostLineComment)
+ {
+ if (isBraceType(braceTypeStack->back(), NAMESPACE_TYPE))
+ {
+ // namespace run-in is always broken.
+ isInLineBreak = true;
+ }
+ else if (braceFormatMode == NONE_MODE)
+ {
+ // should a run-in statement be attached?
+ if (currentLineBeginsWithBrace)
+ formatRunIn();
+ }
+ else if (braceFormatMode == ATTACH_MODE)
+ {
+ // if the brace was not attached?
+ if (formattedLine.length() > 0 && formattedLine[0] == '{'
+ && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE))
+ isInLineBreak = true;
+ }
+ else if (braceFormatMode == RUN_IN_MODE)
+ {
+ // should a run-in statement be attached?
+ if (formattedLine.length() > 0 && formattedLine[0] == '{')
+ formatRunIn();
+ }
+ }
+ else if (!doesLineStartComment)
+ noTrimCommentContinuation = true;
+
+ // ASBeautifier needs to know the following statements
+ if (shouldBreakElseIfs && followingHeader == &AS_ELSE)
+ elseHeaderFollowsComments = true;
+ if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT)
+ caseHeaderFollowsComments = true;
+
+ // appendSequence will write the previous line
+ appendSequence(AS_OPEN_COMMENT);
+ goForward(1);
+
+ // must be done AFTER appendSequence
+
+ // Break before the comment if a header follows the line comment.
+ // But not break if previous line is empty, a comment, or a '{'.
+ if (shouldBreakBlocks
+ && followingHeader != nullptr
+ && !isImmediatelyPostEmptyLine
+ && previousCommandChar != '{')
+ {
+ if (isClosingHeader(followingHeader))
+ {
+ if (!shouldBreakClosingHeaderBlocks)
+ isPrependPostBlockEmptyLineRequested = false;
+ }
+ // if an opening header, break before the comment
+ else
+ isPrependPostBlockEmptyLineRequested = true;
+ }
+
+ if (previousCommandChar == '}')
+ currentHeader = nullptr;
+}
+
+/**
+ * format a comment closer
+ * the comment closer will be appended to the current formattedLine
+ */
+void ASFormatter::formatCommentCloser()
+{
+ assert(isSequenceReached("*/"));
+ isInComment = false;
+ noTrimCommentContinuation = false;
+ isImmediatelyPostComment = true;
+ appendSequence(AS_CLOSE_COMMENT);
+ goForward(1);
+ if (doesLineStartComment
+ && (currentLine.find_first_not_of(" \t", charNum + 1) == string::npos))
+ lineEndsInCommentOnly = true;
+ if (peekNextChar() == '}'
+ && previousCommandChar != ';'
+ && !isBraceType(braceTypeStack->back(), ARRAY_TYPE)
+ && !isInPreprocessor
+ && isOkToBreakBlock(braceTypeStack->back()))
+ {
+ isInLineBreak = true;
+ shouldBreakLineAtNextChar = true;
+ }
+}
+
+/**
+ * format a line comment body
+ * the calling function should have a continue statement after calling this method
+ */
+void ASFormatter::formatLineCommentBody()
+{
+ assert(isInLineComment);
+
+ // append the comment
+ while (charNum < (int) currentLine.length())
+// && !isLineReady // commented out in release 2.04, unnecessary
+ {
+ currentChar = currentLine[charNum];
+ if (currentChar == '\t' && shouldConvertTabs)
+ convertTabToSpaces();
+ appendCurrentChar();
+ ++charNum;
+ }
+
+ // explicitly break a line when a line comment's end is found.
+ if (charNum == (int) currentLine.length())
+ {
+ isInLineBreak = true;
+ isInLineComment = false;
+ isImmediatelyPostLineComment = true;
+ currentChar = 0; //make sure it is a neutral char.
+ }
+}
+
+/**
+ * format a line comment opener
+ * the line comment opener will be appended to the current formattedLine or a new formattedLine as necessary
+ * the calling function should have a continue statement after calling this method
+ */
+void ASFormatter::formatLineCommentOpener()
+{
+ assert(isSequenceReached("//"));
+
+ if ((int) currentLine.length() > charNum + 2
+ && currentLine[charNum + 2] == '\xf2') // check for windows line marker
+ isAppendPostBlockEmptyLineRequested = false;
+
+ isInLineComment = true;
+ isCharImmediatelyPostComment = false;
+ if (previousNonWSChar == '}')
+ resetEndOfStatement();
+
+ // Check for a following header.
+ // For speed do not check multiple comment lines more than once.
+ // For speed do not check shouldBreakBlocks if previous line is empty, a comment, or a '{'.
+ const string* followingHeader = nullptr;
+ if ((lineIsLineCommentOnly
+ && !isImmediatelyPostCommentOnly
+ && isBraceType(braceTypeStack->back(), COMMAND_TYPE))
+ && (shouldBreakElseIfs
+ || isInSwitchStatement()
+ || (shouldBreakBlocks
+ && !isImmediatelyPostEmptyLine
+ && previousCommandChar != '{')))
+ followingHeader = checkForHeaderFollowingComment(currentLine.substr(charNum));
+
+ // do not indent if in column 1 or 2
+ // or in a namespace before the opening brace
+ if ((!shouldIndentCol1Comments && !lineCommentNoIndent)
+ || foundNamespaceHeader)
+ {
+ if (charNum == 0)
+ lineCommentNoIndent = true;
+ else if (charNum == 1 && currentLine[0] == ' ')
+ lineCommentNoIndent = true;
+ }
+ // move comment if spaces were added or deleted
+ if (!lineCommentNoIndent && spacePadNum != 0 && !isInLineBreak)
+ adjustComments();
+ formattedLineCommentNum = formattedLine.length();
+
+ // must be done BEFORE appendSequence
+ // check for run-in statement
+ if (previousCommandChar == '{'
+ && !isImmediatelyPostComment
+ && !isImmediatelyPostLineComment)
+ {
+ if (braceFormatMode == NONE_MODE)
+ {
+ if (currentLineBeginsWithBrace)
+ formatRunIn();
+ }
+ else if (braceFormatMode == RUN_IN_MODE)
+ {
+ if (!lineCommentNoIndent)
+ formatRunIn();
+ else
+ isInLineBreak = true;
+ }
+ else if (braceFormatMode == BREAK_MODE)
+ {
+ if (formattedLine.length() > 0 && formattedLine[0] == '{')
+ isInLineBreak = true;
+ }
+ else
+ {
+ if (currentLineBeginsWithBrace)
+ isInLineBreak = true;
+ }
+ }
+
+ // ASBeautifier needs to know the following statements
+ if (shouldBreakElseIfs && followingHeader == &AS_ELSE)
+ elseHeaderFollowsComments = true;
+ if (followingHeader == &AS_CASE || followingHeader == &AS_DEFAULT)
+ caseHeaderFollowsComments = true;
+
+ // appendSequence will write the previous line
+ appendSequence(AS_OPEN_LINE_COMMENT);
+ goForward(1);
+
+ // must be done AFTER appendSequence
+
+ // Break before the comment if a header follows the line comment.
+ // But do not break if previous line is empty, a comment, or a '{'.
+ if (shouldBreakBlocks
+ && followingHeader != nullptr
+ && !isImmediatelyPostEmptyLine
+ && previousCommandChar != '{')
+ {
+ if (isClosingHeader(followingHeader))
+ {
+ if (!shouldBreakClosingHeaderBlocks)
+ isPrependPostBlockEmptyLineRequested = false;
+ }
+ // if an opening header, break before the comment
+ else
+ isPrependPostBlockEmptyLineRequested = true;
+ }
+
+ if (previousCommandChar == '}')
+ currentHeader = nullptr;
+
+ // if tabbed input don't convert the immediately following tabs to spaces
+ if (getIndentString() == "\t" && lineCommentNoIndent)
+ {
+ while (charNum + 1 < (int) currentLine.length()
+ && currentLine[charNum + 1] == '\t')
+ {
+ currentChar = currentLine[++charNum];
+ appendCurrentChar();
+ }
+ }
+
+ // explicitly break a line when a line comment's end is found.
+ if (charNum + 1 == (int) currentLine.length())
+ {
+ isInLineBreak = true;
+ isInLineComment = false;
+ isImmediatelyPostLineComment = true;
+ currentChar = 0; //make sure it is a neutral char.
+ }
+}
+
+/**
+ * format quote body
+ * the calling function should have a continue statement after calling this method
+ */
+void ASFormatter::formatQuoteBody()
+{
+ assert(isInQuote);
+
+ if (isSpecialChar)
+ {
+ isSpecialChar = false;
+ }
+ else if (currentChar == '\\' && !isInVerbatimQuote)
+ {
+ if (peekNextChar() == ' ') // is this '\' at end of line
+ haveLineContinuationChar = true;
+ else
+ isSpecialChar = true;
+ }
+ else if (isInVerbatimQuote && currentChar == '"')
+ {
+ if (isCStyle())
+ {
+ string delim = ')' + verbatimDelimiter;
+ int delimStart = charNum - delim.length();
+ if (delimStart > 0 && currentLine.substr(delimStart, delim.length()) == delim)
+ {
+ isInQuote = false;
+ isInVerbatimQuote = false;
+ }
+ }
+ else if (isSharpStyle())
+ {
+ if ((int) currentLine.length() > charNum + 1
+ && currentLine[charNum + 1] == '"') // check consecutive quotes
+ {
+ appendSequence("\"\"");
+ goForward(1);
+ return;
+ }
+ isInQuote = false;
+ isInVerbatimQuote = false;
+ }
+ }
+ else if (quoteChar == currentChar)
+ {
+ isInQuote = false;
+ }
+
+ appendCurrentChar();
+
+ // append the text to the ending quoteChar or an escape sequence
+ // tabs in quotes are NOT changed by convert-tabs
+ if (isInQuote && currentChar != '\\')
+ {
+ while (charNum + 1 < (int) currentLine.length()
+ && currentLine[charNum + 1] != quoteChar
+ && currentLine[charNum + 1] != '\\')
+ {
+ currentChar = currentLine[++charNum];
+ appendCurrentChar();
+ }
+ }
+ if (charNum + 1 >= (int) currentLine.length()
+ && currentChar != '\\'
+ && !isInVerbatimQuote)
+ isInQuote = false; // missing closing quote
+}
+
+/**
+ * format a quote opener
+ * the quote opener will be appended to the current formattedLine or a new formattedLine as necessary
+ * the calling function should have a continue statement after calling this method
+ */
+void ASFormatter::formatQuoteOpener()
+{
+ assert(currentChar == '"'
+ || (currentChar == '\'' && !isDigitSeparator(currentLine, charNum)));
+
+ isInQuote = true;
+ quoteChar = currentChar;
+ if (isCStyle() && previousChar == 'R')
+ {
+ int parenPos = currentLine.find('(', charNum);
+ if (parenPos != -1)
+ {
+ isInVerbatimQuote = true;
+ verbatimDelimiter = currentLine.substr(charNum + 1, parenPos - charNum - 1);
+ }
+ }
+ else if (isSharpStyle() && previousChar == '@')
+ isInVerbatimQuote = true;
+
+ // a quote following a brace is an array
+ if (previousCommandChar == '{'
+ && !isImmediatelyPostComment
+ && !isImmediatelyPostLineComment
+ && isNonInStatementArray
+ && !isBraceType(braceTypeStack->back(), SINGLE_LINE_TYPE)
+ && !isWhiteSpace(peekNextChar()))
+ {
+ if (braceFormatMode == NONE_MODE)
+ {
+ if (currentLineBeginsWithBrace)
+ formatRunIn();
+ }
+ else if (braceFormatMode == RUN_IN_MODE)
+ {
+ formatRunIn();
+ }
+ else if (braceFormatMode == BREAK_MODE)
+ {
+ if (formattedLine.length() > 0 && formattedLine[0] == '{')
+ isInLineBreak = true;
+ }
+ else
+ {
+ if (currentLineBeginsWithBrace)
+ isInLineBreak = true;
+ }
+ }
+ previousCommandChar = ' ';
+ appendCurrentChar();
+}
+
+/**
+ * get the next line comment adjustment that results from breaking a closing brace.
+ * the brace must be on the same line as the closing header.
+ * i.e "} else" changed to "} <NL> else".
+ */
+int ASFormatter::getNextLineCommentAdjustment()
+{
+ assert(foundClosingHeader && previousNonWSChar == '}');
+ if (charNum < 1) // "else" is in column 1
+ return 0;
+ size_t lastBrace = currentLine.rfind('}', charNum - 1);
+ if (lastBrace != string::npos)
+ return (lastBrace - charNum); // return a negative number
+ return 0;
+}
+
+// for console build only
+LineEndFormat ASFormatter::getLineEndFormat() const
+{
+ return lineEnd;
+}
+
+/**
+ * get the current line comment adjustment that results from attaching
+ * a closing header to a closing brace.
+ * the brace must be on the line previous to the closing header.
+ * the adjustment is 2 chars, one for the brace and one for the space.
+ * i.e "} <NL> else" changed to "} else".
+ */
+int ASFormatter::getCurrentLineCommentAdjustment()
+{
+ assert(foundClosingHeader && previousNonWSChar == '}');
+ if (charNum < 1)
+ return 2;
+ size_t lastBrace = currentLine.rfind('}', charNum - 1);
+ if (lastBrace == string::npos)
+ return 2;
+ return 0;
+}
+
+/**
+ * get the previous word on a line
+ * the argument 'currPos' must point to the current position.
+ *
+ * @return is the previous word or an empty string if none found.
+ */
+string ASFormatter::getPreviousWord(const string& line, int currPos) const
+{
+ // get the last legal word (may be a number)
+ if (currPos == 0)
+ return string();
+
+ size_t end = line.find_last_not_of(" \t", currPos - 1);
+ if (end == string::npos || !isLegalNameChar(line[end]))
+ return string();
+
+ int start; // start of the previous word
+ for (start = end; start > -1; start--)
+ {
+ if (!isLegalNameChar(line[start]) || line[start] == '.')
+ break;
+ }
+ start++;
+
+ return (line.substr(start, end - start + 1));
+}
+
+/**
+ * check if a line break is needed when a closing brace
+ * is followed by a closing header.
+ * the break depends on the braceFormatMode and other factors.
+ */
+void ASFormatter::isLineBreakBeforeClosingHeader()
+{
+ assert(foundClosingHeader && previousNonWSChar == '}');
+
+ if (currentHeader == &AS_WHILE && shouldAttachClosingWhile)
+ {
+ appendClosingHeader();
+ return;
+ }
+
+ if (braceFormatMode == BREAK_MODE
+ || braceFormatMode == RUN_IN_MODE
+ || attachClosingBraceMode)
+ {
+ isInLineBreak = true;
+ }
+ else if (braceFormatMode == NONE_MODE)
+ {
+ if (shouldBreakClosingHeaderBraces
+ || getBraceIndent() || getBlockIndent())
+ {
+ isInLineBreak = true;
+ }
+ else
+ {
+ appendSpacePad();
+ // is closing brace broken?
+ size_t i = currentLine.find_first_not_of(" \t");
+ if (i != string::npos && currentLine[i] == '}')
+ isInLineBreak = false;
+
+ if (shouldBreakBlocks)
+ isAppendPostBlockEmptyLineRequested = false;
+ }
+ }
+ // braceFormatMode == ATTACH_MODE, LINUX_MODE
+ else
+ {
+ if (shouldBreakClosingHeaderBraces
+ || getBraceIndent() || getBlockIndent())
+ {
+ isInLineBreak = true;
+ }
+ else
+ {
+ appendClosingHeader();
+ if (shouldBreakBlocks)
+ isAppendPostBlockEmptyLineRequested = false;
+ }
+ }
+}
+
+/**
+ * Append a closing header to the previous closing brace, if possible
+ */
+void ASFormatter::appendClosingHeader()
+{
+ // if a blank line does not precede this
+ // or last line is not a one line block, attach header
+ bool previousLineIsEmpty = isEmptyLine(formattedLine);
+ int previousLineIsOneLineBlock = 0;
+ size_t firstBrace = findNextChar(formattedLine, '{');
+ if (firstBrace != string::npos)
+ previousLineIsOneLineBlock = isOneLineBlockReached(formattedLine, firstBrace);
+ if (!previousLineIsEmpty
+ && previousLineIsOneLineBlock == 0)
+ {
+ isInLineBreak = false;
+ appendSpacePad();
+ spacePadNum = 0; // don't count as comment padding
+ }
+}
+
+/**
+ * Add braces to a single line statement following a header.
+ * braces are not added if the proper conditions are not met.
+ * braces are added to the currentLine.
+ */
+bool ASFormatter::addBracesToStatement()
+{
+ assert(isImmediatelyPostHeader);
+
+ if (currentHeader != &AS_IF
+ && currentHeader != &AS_ELSE
+ && currentHeader != &AS_FOR
+ && currentHeader != &AS_WHILE
+ && currentHeader != &AS_DO
+ && currentHeader != &AS_FOREACH
+ && currentHeader != &AS_QFOREACH
+ && currentHeader != &AS_QFOREVER
+ && currentHeader != &AS_FOREVER)
+ return false;
+
+ if (currentHeader == &AS_WHILE && foundClosingHeader) // do-while
+ return false;
+
+ // do not brace an empty statement
+ if (currentChar == ';')
+ return false;
+
+ // do not add if a header follows
+ if (isCharPotentialHeader(currentLine, charNum))
+ if (findHeader(headers) != nullptr)
+ return false;
+
+ // find the next semi-colon
+ size_t nextSemiColon = charNum;
+ if (currentChar != ';')
+ nextSemiColon = findNextChar(currentLine, ';', charNum + 1);
+ if (nextSemiColon == string::npos)
+ return false;
+
+ // add closing brace before changing the line length
+ if (nextSemiColon == currentLine.length() - 1)
+ currentLine.append(" }");
+ else
+ currentLine.insert(nextSemiColon + 1, " }");
+ // add opening brace
+ currentLine.insert(charNum, "{ ");
+ assert(computeChecksumIn("{}"));
+ currentChar = '{';
+ if ((int) currentLine.find_first_not_of(" \t") == charNum)
+ currentLineBeginsWithBrace = true;
+ // remove extra spaces
+ if (!shouldAddOneLineBraces)
+ {
+ size_t lastText = formattedLine.find_last_not_of(" \t");
+ if ((formattedLine.length() - 1) - lastText > 1)
+ formattedLine.erase(lastText + 1);
+ }
+ return true;
+}
+
+/**
+ * Remove braces from a single line statement following a header.
+ * braces are not removed if the proper conditions are not met.
+ * The first brace is replaced by a space.
+ */
+bool ASFormatter::removeBracesFromStatement()
+{
+ assert(isImmediatelyPostHeader);
+ assert(currentChar == '{');
+
+ if (currentHeader != &AS_IF
+ && currentHeader != &AS_ELSE
+ && currentHeader != &AS_FOR
+ && currentHeader != &AS_WHILE
+ && currentHeader != &AS_FOREACH)
+ return false;
+
+ if (currentHeader == &AS_WHILE && foundClosingHeader) // do-while
+ return false;
+
+ bool isFirstLine = true;
+ string nextLine_;
+ // leave nextLine_ empty if end of line comment follows
+ if (!isBeforeAnyLineEndComment(charNum) || currentLineBeginsWithBrace)
+ nextLine_ = currentLine.substr(charNum + 1);
+ size_t nextChar = 0;
+
+ // find the first non-blank text
+ ASPeekStream stream(sourceIterator);
+ while (stream.hasMoreLines() || isFirstLine)
+ {
+ if (isFirstLine)
+ isFirstLine = false;
+ else
+ {
+ nextLine_ = stream.peekNextLine();
+ nextChar = 0;
+ }
+
+ nextChar = nextLine_.find_first_not_of(" \t", nextChar);
+ if (nextChar != string::npos)
+ break;
+ }
+
+ // don't remove if comments or a header follow the brace
+ if ((nextLine_.compare(nextChar, 2, "/*") == 0)
+ || (nextLine_.compare(nextChar, 2, "//") == 0)
+ || (isCharPotentialHeader(nextLine_, nextChar)
+ && ASBase::findHeader(nextLine_, nextChar, headers) != nullptr))
+ return false;
+
+ // find the next semi-colon
+ size_t nextSemiColon = nextChar;
+ if (nextLine_[nextChar] != ';')
+ nextSemiColon = findNextChar(nextLine_, ';', nextChar + 1);
+ if (nextSemiColon == string::npos)
+ return false;
+
+ // find the closing brace
+ isFirstLine = true;
+ nextChar = nextSemiColon + 1;
+ while (stream.hasMoreLines() || isFirstLine)
+ {
+ if (isFirstLine)
+ isFirstLine = false;
+ else
+ {
+ nextLine_ = stream.peekNextLine();
+ nextChar = 0;
+ }
+ nextChar = nextLine_.find_first_not_of(" \t", nextChar);
+ if (nextChar != string::npos)
+ break;
+ }
+ if (nextLine_.length() == 0 || nextLine_[nextChar] != '}')
+ return false;
+
+ // remove opening brace
+ currentLine[charNum] = currentChar = ' ';
+ assert(adjustChecksumIn(-'{'));
+ return true;
+}
+
+/**
+ * Find the next character that is not in quotes or a comment.
+ *
+ * @param line the line to be searched.
+ * @param searchChar the char to find.
+ * @param searchStart the start position on the line (default is 0).
+ * @return the position on the line or string::npos if not found.
+ */
+size_t ASFormatter::findNextChar(const string& line, char searchChar, int searchStart /*0*/) const
+{
+ // find the next searchChar
+ size_t i;
+ for (i = searchStart; i < line.length(); i++)
+ {
+ if (line.compare(i, 2, "//") == 0)
+ return string::npos;
+ if (line.compare(i, 2, "/*") == 0)
+ {
+ size_t endComment = line.find("*/", i + 2);
+ if (endComment == string::npos)
+ return string::npos;
+ i = endComment + 2;
+ if (i >= line.length())
+ return string::npos;
+ }
+ if (line[i] == '"'
+ || (line[i] == '\'' && !isDigitSeparator(line, i)))
+ {
+ char quote = line[i];
+ while (i < line.length())
+ {
+ size_t endQuote = line.find(quote, i + 1);
+ if (endQuote == string::npos)
+ return string::npos;
+ i = endQuote;
+ if (line[endQuote - 1] != '\\') // check for '\"'
+ break;
+ if (line[endQuote - 2] == '\\') // check for '\\'
+ break;
+ }
+ }
+
+ if (line[i] == searchChar)
+ break;
+
+ // for now don't process C# 'delegate' braces
+ // do this last in case the search char is a '{'
+ if (line[i] == '{')
+ return string::npos;
+ }
+ if (i >= line.length()) // didn't find searchChar
+ return string::npos;
+
+ return i;
+}
+
+/**
+ * Look ahead in the file to see if a struct has access modifiers.
+ *
+ * @param firstLine a reference to the line to indent.
+ * @param index the current line index.
+ * @return true if the struct has access modifiers.
+ */
+bool ASFormatter::isStructAccessModified(const string& firstLine, size_t index) const
+{
+ assert(firstLine[index] == '{');
+ assert(isCStyle());
+
+ bool isFirstLine = true;
+ size_t braceCount = 1;
+ string nextLine_ = firstLine.substr(index + 1);
+ ASPeekStream stream(sourceIterator);
+
+ // find the first non-blank text, bypassing all comments and quotes.
+ bool isInComment_ = false;
+ bool isInQuote_ = false;
+ char quoteChar_ = ' ';
+ while (stream.hasMoreLines() || isFirstLine)
+ {
+ if (isFirstLine)
+ isFirstLine = false;
+ else
+ nextLine_ = stream.peekNextLine();
+ // parse the line
+ for (size_t i = 0; i < nextLine_.length(); i++)
+ {
+ if (isWhiteSpace(nextLine_[i]))
+ continue;
+ if (nextLine_.compare(i, 2, "/*") == 0)
+ isInComment_ = true;
+ if (isInComment_)
+ {
+ if (nextLine_.compare(i, 2, "*/") == 0)
+ {
+ isInComment_ = false;
+ ++i;
+ }
+ continue;
+ }
+ if (nextLine_[i] == '\\')
+ {
+ ++i;
+ continue;
+ }
+
+ if (isInQuote_)
+ {
+ if (nextLine_[i] == quoteChar_)
+ isInQuote_ = false;
+ continue;
+ }
+
+ if (nextLine_[i] == '"'
+ || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
+ {
+ isInQuote_ = true;
+ quoteChar_ = nextLine_[i];
+ continue;
+ }
+ if (nextLine_.compare(i, 2, "//") == 0)
+ {
+ i = nextLine_.length();
+ continue;
+ }
+ // handle braces
+ if (nextLine_[i] == '{')
+ ++braceCount;
+ if (nextLine_[i] == '}')
+ --braceCount;
+ if (braceCount == 0)
+ return false;
+ // check for access modifiers
+ if (isCharPotentialHeader(nextLine_, i))
+ {
+ if (findKeyword(nextLine_, i, AS_PUBLIC)
+ || findKeyword(nextLine_, i, AS_PRIVATE)
+ || findKeyword(nextLine_, i, AS_PROTECTED))
+ return true;
+ string name = getCurrentWord(nextLine_, i);
+ i += name.length() - 1;
+ }
+ } // end of for loop
+ } // end of while loop
+
+ return false;
+}
+
+/**
+* Look ahead in the file to see if a preprocessor block is indentable.
+*
+* @param firstLine a reference to the line to indent.
+* @param index the current line index.
+* @return true if the block is indentable.
+*/
+bool ASFormatter::isIndentablePreprocessorBlock(const string& firstLine, size_t index)
+{
+ assert(firstLine[index] == '#');
+
+ bool isFirstLine = true;
+ bool isInIndentableBlock = false;
+ bool blockContainsBraces = false;
+ bool blockContainsDefineContinuation = false;
+ bool isInClassConstructor = false;
+ bool isPotentialHeaderGuard = false; // ifndef is first preproc statement
+ bool isPotentialHeaderGuard2 = false; // define is within the first proproc
+ int numBlockIndents = 0;
+ int lineParenCount = 0;
+ string nextLine_ = firstLine.substr(index);
+ auto stream = make_shared<ASPeekStream>(sourceIterator);
+
+ // find end of the block, bypassing all comments and quotes.
+ bool isInComment_ = false;
+ bool isInQuote_ = false;
+ char quoteChar_ = ' ';
+ while (stream->hasMoreLines() || isFirstLine)
+ {
+ if (isFirstLine)
+ isFirstLine = false;
+ else
+ nextLine_ = stream->peekNextLine();
+ // parse the line
+ for (size_t i = 0; i < nextLine_.length(); i++)
+ {
+ if (isWhiteSpace(nextLine_[i]))
+ continue;
+ if (nextLine_.compare(i, 2, "/*") == 0)
+ isInComment_ = true;
+ if (isInComment_)
+ {
+ if (nextLine_.compare(i, 2, "*/") == 0)
+ {
+ isInComment_ = false;
+ ++i;
+ }
+ continue;
+ }
+ if (nextLine_[i] == '\\')
+ {
+ ++i;
+ continue;
+ }
+ if (isInQuote_)
+ {
+ if (nextLine_[i] == quoteChar_)
+ isInQuote_ = false;
+ continue;
+ }
+
+ if (nextLine_[i] == '"'
+ || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
+ {
+ isInQuote_ = true;
+ quoteChar_ = nextLine_[i];
+ continue;
+ }
+ if (nextLine_.compare(i, 2, "//") == 0)
+ {
+ i = nextLine_.length();
+ continue;
+ }
+ // handle preprocessor statement
+ if (nextLine_[i] == '#')
+ {
+ string preproc = ASBeautifier::extractPreprocessorStatement(nextLine_);
+ if (preproc.length() >= 2 && preproc.substr(0, 2) == "if") // #if, #ifdef, #ifndef
+ {
+ numBlockIndents += 1;
+ isInIndentableBlock = true;
+ // flag first preprocessor conditional for header include guard check
+ if (!processedFirstConditional)
+ {
+ processedFirstConditional = true;
+ isFirstPreprocConditional = true;
+ if (isNDefPreprocStatement(nextLine_, preproc))
+ isPotentialHeaderGuard = true;
+ }
+ }
+ else if (preproc == "endif")
+ {
+ if (numBlockIndents > 0)
+ numBlockIndents -= 1;
+ // must exit BOTH loops
+ if (numBlockIndents == 0)
+ goto EndOfWhileLoop;
+ }
+ else if (preproc == "define")
+ {
+ if (nextLine_[nextLine_.length() - 1] == '\\')
+ blockContainsDefineContinuation = true;
+ // check for potential header include guards
+ else if (isPotentialHeaderGuard && numBlockIndents == 1)
+ isPotentialHeaderGuard2 = true;
+ }
+ i = nextLine_.length();
+ continue;
+ }
+ // handle exceptions
+ if (nextLine_[i] == '{' || nextLine_[i] == '}')
+ blockContainsBraces = true;
+ else if (nextLine_[i] == '(')
+ ++lineParenCount;
+ else if (nextLine_[i] == ')')
+ --lineParenCount;
+ else if (nextLine_[i] == ':')
+ {
+ // check for '::'
+ if (nextLine_.length() > i && nextLine_[i + 1] == ':')
+ ++i;
+ else
+ isInClassConstructor = true;
+ }
+ // bypass unnecessary parsing - must exit BOTH loops
+ if (blockContainsBraces || isInClassConstructor || blockContainsDefineContinuation)
+ goto EndOfWhileLoop;
+ } // end of for loop, end of line
+ if (lineParenCount != 0)
+ break;
+ } // end of while loop
+EndOfWhileLoop:
+ preprocBlockEnd = sourceIterator->tellg();
+ if (preprocBlockEnd < 0)
+ preprocBlockEnd = sourceIterator->getStreamLength();
+ if (blockContainsBraces
+ || isInClassConstructor
+ || blockContainsDefineContinuation
+ || lineParenCount != 0
+ || numBlockIndents != 0)
+ isInIndentableBlock = false;
+ // find next executable instruction
+ // this WILL RESET the get pointer
+ string nextText = peekNextText("", false, stream);
+ // bypass header include guards
+ if (isFirstPreprocConditional)
+ {
+ isFirstPreprocConditional = false;
+ if (nextText.empty() && isPotentialHeaderGuard2)
+ {
+ isInIndentableBlock = false;
+ preprocBlockEnd = 0;
+ }
+ }
+ // this allows preprocessor blocks within this block to be indented
+ if (!isInIndentableBlock)
+ preprocBlockEnd = 0;
+ // peekReset() is done by previous peekNextText()
+ return isInIndentableBlock;
+}
+
+bool ASFormatter::isNDefPreprocStatement(const string& nextLine_, const string& preproc) const
+{
+ if (preproc == "ifndef")
+ return true;
+ // check for '!defined'
+ if (preproc == "if")
+ {
+ size_t i = nextLine_.find('!');
+ if (i == string::npos)
+ return false;
+ i = nextLine_.find_first_not_of(" \t", ++i);
+ if (i != string::npos && nextLine_.compare(i, 7, "defined") == 0)
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Check to see if this is an EXEC SQL statement.
+ *
+ * @param line a reference to the line to indent.
+ * @param index the current line index.
+ * @return true if the statement is EXEC SQL.
+ */
+bool ASFormatter::isExecSQL(const string& line, size_t index) const
+{
+ if (line[index] != 'e' && line[index] != 'E') // quick check to reject most
+ return false;
+ string word;
+ if (isCharPotentialHeader(line, index))
+ word = getCurrentWord(line, index);
+ for (size_t i = 0; i < word.length(); i++)
+ word[i] = (char) toupper(word[i]);
+ if (word != "EXEC")
+ return false;
+ size_t index2 = index + word.length();
+ index2 = line.find_first_not_of(" \t", index2);
+ if (index2 == string::npos)
+ return false;
+ word.erase();
+ if (isCharPotentialHeader(line, index2))
+ word = getCurrentWord(line, index2);
+ for (size_t i = 0; i < word.length(); i++)
+ word[i] = (char) toupper(word[i]);
+ if (word != "SQL")
+ return false;
+ return true;
+}
+
+/**
+ * The continuation lines must be adjusted so the leading spaces
+ * is equivalent to the text on the opening line.
+ *
+ * Updates currentLine and charNum.
+ */
+void ASFormatter::trimContinuationLine()
+{
+ size_t len = currentLine.length();
+ size_t tabSize = getTabLength();
+ charNum = 0;
+
+ if (leadingSpaces > 0 && len > 0)
+ {
+ size_t i;
+ size_t continuationIncrementIn = 0;
+ for (i = 0; (i < len) && (i + continuationIncrementIn < leadingSpaces); i++)
+ {
+ if (!isWhiteSpace(currentLine[i])) // don't delete any text
+ {
+ if (i < continuationIncrementIn)
+ leadingSpaces = i + tabIncrementIn;
+ continuationIncrementIn = tabIncrementIn;
+ break;
+ }
+ if (currentLine[i] == '\t')
+ continuationIncrementIn += tabSize - 1 - ((continuationIncrementIn + i) % tabSize);
+ }
+
+ if ((int) continuationIncrementIn == tabIncrementIn)
+ charNum = i;
+ else
+ {
+ // build a new line with the equivalent leading chars
+ string newLine;
+ int leadingChars = 0;
+ if ((int) leadingSpaces > tabIncrementIn)
+ leadingChars = leadingSpaces - tabIncrementIn;
+ newLine.append(leadingChars, ' ');
+ newLine.append(currentLine, i, len - i);
+ currentLine = newLine;
+ charNum = leadingChars;
+ if (currentLine.length() == 0)
+ currentLine = string(" "); // a null is inserted if this is not done
+ }
+ if (i >= len)
+ charNum = 0;
+ }
+}
+
+/**
+ * Determine if a header is a closing header
+ *
+ * @return true if the header is a closing header.
+ */
+bool ASFormatter::isClosingHeader(const string* header) const
+{
+ return (header == &AS_ELSE
+ || header == &AS_CATCH
+ || header == &AS_FINALLY);
+}
+
+/**
+ * Determine if a * following a closing paren is immediately.
+ * after a cast. If so it is a deference and not a multiply.
+ * e.g. "(int*) *ptr" is a deference.
+ */
+bool ASFormatter::isImmediatelyPostCast() const
+{
+ assert(previousNonWSChar == ')' && currentChar == '*');
+ // find preceding closing paren on currentLine or readyFormattedLine
+ string line; // currentLine or readyFormattedLine
+ size_t paren = currentLine.rfind(')', charNum);
+ if (paren != string::npos)
+ line = currentLine;
+ // if not on currentLine it must be on the previous line
+ else
+ {
+ line = readyFormattedLine;
+ paren = line.rfind(')');
+ if (paren == string::npos)
+ return false;
+ }
+ if (paren == 0)
+ return false;
+
+ // find character preceding the closing paren
+ size_t lastChar = line.find_last_not_of(" \t", paren - 1);
+ if (lastChar == string::npos)
+ return false;
+ // check for pointer cast
+ if (line[lastChar] == '*')
+ return true;
+ return false;
+}
+
+/**
+ * Determine if a < is a template definition or instantiation.
+ * Sets the class variables isInTemplate and templateDepth.
+ */
+void ASFormatter::checkIfTemplateOpener()
+{
+ assert(!isInTemplate && currentChar == '<');
+
+ // find first char after the '<' operators
+ size_t firstChar = currentLine.find_first_not_of("< \t", charNum);
+ if (firstChar == string::npos
+ || currentLine[firstChar] == '=')
+ {
+ // this is not a template -> leave...
+ isInTemplate = false;
+ return;
+ }
+
+ bool isFirstLine = true;
+ int parenDepth_ = 0;
+ int maxTemplateDepth = 0;
+ templateDepth = 0;
+ string nextLine_ = currentLine.substr(charNum);
+ ASPeekStream stream(sourceIterator);
+
+ // find the angle braces, bypassing all comments and quotes.
+ bool isInComment_ = false;
+ bool isInQuote_ = false;
+ char quoteChar_ = ' ';
+ while (stream.hasMoreLines() || isFirstLine)
+ {
+ if (isFirstLine)
+ isFirstLine = false;
+ else
+ nextLine_ = stream.peekNextLine();
+ // parse the line
+ for (size_t i = 0; i < nextLine_.length(); i++)
+ {
+ char currentChar_ = nextLine_[i];
+ if (isWhiteSpace(currentChar_))
+ continue;
+ if (nextLine_.compare(i, 2, "/*") == 0)
+ isInComment_ = true;
+ if (isInComment_)
+ {
+ if (nextLine_.compare(i, 2, "*/") == 0)
+ {
+ isInComment_ = false;
+ ++i;
+ }
+ continue;
+ }
+ if (currentChar_ == '\\')
+ {
+ ++i;
+ continue;
+ }
+
+ if (isInQuote_)
+ {
+ if (currentChar_ == quoteChar_)
+ isInQuote_ = false;
+ continue;
+ }
+
+ if (currentChar_ == '"'
+ || (currentChar_ == '\'' && !isDigitSeparator(nextLine_, i)))
+ {
+ isInQuote_ = true;
+ quoteChar_ = currentChar_;
+ continue;
+ }
+ if (nextLine_.compare(i, 2, "//") == 0)
+ {
+ i = nextLine_.length();
+ continue;
+ }
+
+ // not in a comment or quote
+ if (currentChar_ == '<')
+ {
+ ++templateDepth;
+ ++maxTemplateDepth;
+ continue;
+ }
+ else if (currentChar_ == '>')
+ {
+ --templateDepth;
+ if (templateDepth == 0)
+ {
+ if (parenDepth_ == 0)
+ {
+ // this is a template!
+ isInTemplate = true;
+ templateDepth = maxTemplateDepth;
+ }
+ return;
+ }
+ continue;
+ }
+ else if (currentChar_ == '(' || currentChar_ == ')')
+ {
+ if (currentChar_ == '(')
+ ++parenDepth_;
+ else
+ --parenDepth_;
+ if (parenDepth_ >= 0)
+ continue;
+ // this is not a template -> leave...
+ isInTemplate = false;
+ templateDepth = 0;
+ return;
+ }
+ else if (nextLine_.compare(i, 2, AS_AND) == 0
+ || nextLine_.compare(i, 2, AS_OR) == 0)
+ {
+ // this is not a template -> leave...
+ isInTemplate = false;
+ templateDepth = 0;
+ return;
+ }
+ else if (currentChar_ == ',' // comma, e.g. A<int, char>
+ || currentChar_ == '&' // reference, e.g. A<int&>
+ || currentChar_ == '*' // pointer, e.g. A<int*>
+ || currentChar_ == '^' // C++/CLI managed pointer, e.g. A<int^>
+ || currentChar_ == ':' // ::, e.g. std::string
+ || currentChar_ == '=' // assign e.g. default parameter
+ || currentChar_ == '[' // [] e.g. string[]
+ || currentChar_ == ']' // [] e.g. string[]
+ || currentChar_ == '(' // (...) e.g. function definition
+ || currentChar_ == ')' // (...) e.g. function definition
+ || (isJavaStyle() && currentChar_ == '?') // Java wildcard
+ )
+ {
+ continue;
+ }
+ else if (!isLegalNameChar(currentChar_))
+ {
+ // this is not a template -> leave...
+ isInTemplate = false;
+ templateDepth = 0;
+ return;
+ }
+ string name = getCurrentWord(nextLine_, i);
+ i += name.length() - 1;
+ } // end for loop
+ } // end while loop
+}
+
+void ASFormatter::updateFormattedLineSplitPoints(char appendedChar)
+{
+ assert(maxCodeLength != string::npos);
+ assert(formattedLine.length() > 0);
+
+ if (!isOkToSplitFormattedLine())
+ return;
+
+ char nextChar = peekNextChar();
+
+ // don't split before an end of line comment
+ if (nextChar == '/')
+ return;
+
+ // don't split before or after a brace
+ if (appendedChar == '{' || appendedChar == '}'
+ || previousNonWSChar == '{' || previousNonWSChar == '}'
+ || nextChar == '{' || nextChar == '}'
+ || currentChar == '{' || currentChar == '}') // currentChar tests for an appended brace
+ return;
+
+ // don't split before or after a block paren
+ if (appendedChar == '[' || appendedChar == ']'
+ || previousNonWSChar == '['
+ || nextChar == '[' || nextChar == ']')
+ return;
+
+ if (isWhiteSpace(appendedChar))
+ {
+ if (nextChar != ')' // space before a closing paren
+ && nextChar != '(' // space before an opening paren
+ && nextChar != '/' // space before a comment
+ && nextChar != ':' // space before a colon
+ && currentChar != ')' // appended space before and after a closing paren
+ && currentChar != '(' // appended space before and after a opening paren
+ && previousNonWSChar != '(' // decided at the '('
+ // don't break before a pointer or reference aligned to type
+ && !(nextChar == '*'
+ && !isCharPotentialOperator(previousNonWSChar)
+ && pointerAlignment == PTR_ALIGN_TYPE)
+ && !(nextChar == '&'
+ && !isCharPotentialOperator(previousNonWSChar)
+ && (referenceAlignment == REF_ALIGN_TYPE
+ || (referenceAlignment == REF_SAME_AS_PTR && pointerAlignment == PTR_ALIGN_TYPE)))
+ )
+ {
+ if (formattedLine.length() - 1 <= maxCodeLength)
+ maxWhiteSpace = formattedLine.length() - 1;
+ else
+ maxWhiteSpacePending = formattedLine.length() - 1;
+ }
+ }
+ // unpadded closing parens may split after the paren (counts as whitespace)
+ else if (appendedChar == ')')
+ {
+ if (nextChar != ')'
+ && nextChar != ' '
+ && nextChar != ';'
+ && nextChar != ','
+ && nextChar != '.'
+ && !(nextChar == '-' && pointerSymbolFollows())) // check for ->
+ {
+ if (formattedLine.length() <= maxCodeLength)
+ maxWhiteSpace = formattedLine.length();
+ else
+ maxWhiteSpacePending = formattedLine.length();
+ }
+ }
+ // unpadded commas may split after the comma
+ else if (appendedChar == ',')
+ {
+ if (formattedLine.length() <= maxCodeLength)
+ maxComma = formattedLine.length();
+ else
+ maxCommaPending = formattedLine.length();
+ }
+ else if (appendedChar == '(')
+ {
+ if (nextChar != ')' && nextChar != '(' && nextChar != '"' && nextChar != '\'')
+ {
+ // if follows an operator break before
+ size_t parenNum;
+ if (isCharPotentialOperator(previousNonWSChar))
+ parenNum = formattedLine.length() - 1;
+ else
+ parenNum = formattedLine.length();
+ if (formattedLine.length() <= maxCodeLength)
+ maxParen = parenNum;
+ else
+ maxParenPending = parenNum;
+ }
+ }
+ else if (appendedChar == ';')
+ {
+ if (nextChar != ' ' && nextChar != '}' && nextChar != '/') // check for following comment
+ {
+ if (formattedLine.length() <= maxCodeLength)
+ maxSemi = formattedLine.length();
+ else
+ maxSemiPending = formattedLine.length();
+ }
+ }
+}
+
+void ASFormatter::updateFormattedLineSplitPointsOperator(const string& sequence)
+{
+ assert(maxCodeLength != string::npos);
+ assert(formattedLine.length() > 0);
+
+ if (!isOkToSplitFormattedLine())
+ return;
+
+ char nextChar = peekNextChar();
+
+ // don't split before an end of line comment
+ if (nextChar == '/')
+ return;
+
+ // check for logical conditional
+ if (sequence == "||" || sequence == "&&" || sequence == "or" || sequence == "and")
+ {
+ if (shouldBreakLineAfterLogical)
+ {
+ if (formattedLine.length() <= maxCodeLength)
+ maxAndOr = formattedLine.length();
+ else
+ maxAndOrPending = formattedLine.length();
+ }
+ else
+ {
+ // adjust for leading space in the sequence
+ size_t sequenceLength = sequence.length();
+ if (formattedLine.length() > sequenceLength
+ && isWhiteSpace(formattedLine[formattedLine.length() - sequenceLength - 1]))
+ sequenceLength++;
+ if (formattedLine.length() - sequenceLength <= maxCodeLength)
+ maxAndOr = formattedLine.length() - sequenceLength;
+ else
+ maxAndOrPending = formattedLine.length() - sequenceLength;
+ }
+ }
+ // comparison operators will split after the operator (counts as whitespace)
+ else if (sequence == "==" || sequence == "!=" || sequence == ">=" || sequence == "<=")
+ {
+ if (formattedLine.length() <= maxCodeLength)
+ maxWhiteSpace = formattedLine.length();
+ else
+ maxWhiteSpacePending = formattedLine.length();
+ }
+ // unpadded operators that will split BEFORE the operator (counts as whitespace)
+ else if (sequence == "+" || sequence == "-" || sequence == "?")
+ {
+ if (charNum > 0
+ && !(sequence == "+" && isInExponent())
+ && !(sequence == "-" && isInExponent())
+ && (isLegalNameChar(currentLine[charNum - 1])
+ || currentLine[charNum - 1] == ')'
+ || currentLine[charNum - 1] == ']'
+ || currentLine[charNum - 1] == '\"'))
+ {
+ if (formattedLine.length() - 1 <= maxCodeLength)
+ maxWhiteSpace = formattedLine.length() - 1;
+ else
+ maxWhiteSpacePending = formattedLine.length() - 1;
+ }
+ }
+ // unpadded operators that will USUALLY split AFTER the operator (counts as whitespace)
+ else if (sequence == "=" || sequence == ":")
+ {
+ // split BEFORE if the line is too long
+ // do NOT use <= here, must allow for a brace attached to an array
+ size_t splitPoint = 0;
+ if (formattedLine.length() < maxCodeLength)
+ splitPoint = formattedLine.length();
+ else
+ splitPoint = formattedLine.length() - 1;
+ // padded or unpadded arrays
+ if (previousNonWSChar == ']')
+ {
+ if (formattedLine.length() - 1 <= maxCodeLength)
+ maxWhiteSpace = splitPoint;
+ else
+ maxWhiteSpacePending = splitPoint;
+ }
+ else if (charNum > 0
+ && (isLegalNameChar(currentLine[charNum - 1])
+ || currentLine[charNum - 1] == ')'
+ || currentLine[charNum - 1] == ']'))
+ {
+ if (formattedLine.length() <= maxCodeLength)
+ maxWhiteSpace = splitPoint;
+ else
+ maxWhiteSpacePending = splitPoint;
+ }
+ }
+}
+
+/**
+ * Update the split point when a pointer or reference is formatted.
+ * The argument is the maximum index of the last whitespace character.
+ */
+void ASFormatter::updateFormattedLineSplitPointsPointerOrReference(size_t index)
+{
+ assert(maxCodeLength != string::npos);
+ assert(formattedLine.length() > 0);
+ assert(index < formattedLine.length());
+
+ if (!isOkToSplitFormattedLine())
+ return;
+
+ if (index < maxWhiteSpace) // just in case
+ return;
+
+ if (index <= maxCodeLength)
+ maxWhiteSpace = index;
+ else
+ maxWhiteSpacePending = index;
+}
+
+bool ASFormatter::isOkToSplitFormattedLine()
+{
+ assert(maxCodeLength != string::npos);
+ // Is it OK to split the line?
+ if (shouldKeepLineUnbroken
+ || isInLineComment
+ || isInComment
+ || isInQuote
+ || isInCase
+ || isInPreprocessor
+ || isInExecSQL
+ || isInAsm || isInAsmOneLine || isInAsmBlock
+ || isInTemplate)
+ return false;
+
+ if (!isOkToBreakBlock(braceTypeStack->back()) && currentChar != '{')
+ {
+ shouldKeepLineUnbroken = true;
+ clearFormattedLineSplitPoints();
+ return false;
+ }
+ if (isBraceType(braceTypeStack->back(), ARRAY_TYPE))
+ {
+ shouldKeepLineUnbroken = true;
+ if (!isBraceType(braceTypeStack->back(), ARRAY_NIS_TYPE))
+ clearFormattedLineSplitPoints();
+ return false;
+ }
+ return true;
+}
+
+/* This is called if the option maxCodeLength is set.
+ */
+void ASFormatter::testForTimeToSplitFormattedLine()
+{
+ // DO NOT ASSERT maxCodeLength HERE
+ // should the line be split
+ if (formattedLine.length() > maxCodeLength && !isLineReady)
+ {
+ size_t splitPoint = findFormattedLineSplitPoint();
+ if (splitPoint > 0 && splitPoint < formattedLine.length())
+ {
+ string splitLine = formattedLine.substr(splitPoint);
+ formattedLine = formattedLine.substr(0, splitPoint);
+ breakLine(true);
+ formattedLine = splitLine;
+ // if break-blocks is requested and this is a one-line statement
+ string nextWord = ASBeautifier::getNextWord(currentLine, charNum - 1);
+ if (isAppendPostBlockEmptyLineRequested
+ && (nextWord == "break" || nextWord == "continue"))
+ {
+ isAppendPostBlockEmptyLineRequested = false;
+ isPrependPostBlockEmptyLineRequested = true;
+ }
+ else
+ isPrependPostBlockEmptyLineRequested = false;
+ // adjust max split points
+ maxAndOr = (maxAndOr > splitPoint) ? (maxAndOr - splitPoint) : 0;
+ maxSemi = (maxSemi > splitPoint) ? (maxSemi - splitPoint) : 0;
+ maxComma = (maxComma > splitPoint) ? (maxComma - splitPoint) : 0;
+ maxParen = (maxParen > splitPoint) ? (maxParen - splitPoint) : 0;
+ maxWhiteSpace = (maxWhiteSpace > splitPoint) ? (maxWhiteSpace - splitPoint) : 0;
+ if (maxSemiPending > 0)
+ {
+ maxSemi = (maxSemiPending > splitPoint) ? (maxSemiPending - splitPoint) : 0;
+ maxSemiPending = 0;
+ }
+ if (maxAndOrPending > 0)
+ {
+ maxAndOr = (maxAndOrPending > splitPoint) ? (maxAndOrPending - splitPoint) : 0;
+ maxAndOrPending = 0;
+ }
+ if (maxCommaPending > 0)
+ {
+ maxComma = (maxCommaPending > splitPoint) ? (maxCommaPending - splitPoint) : 0;
+ maxCommaPending = 0;
+ }
+ if (maxParenPending > 0)
+ {
+ maxParen = (maxParenPending > splitPoint) ? (maxParenPending - splitPoint) : 0;
+ maxParenPending = 0;
+ }
+ if (maxWhiteSpacePending > 0)
+ {
+ maxWhiteSpace = (maxWhiteSpacePending > splitPoint) ? (maxWhiteSpacePending - splitPoint) : 0;
+ maxWhiteSpacePending = 0;
+ }
+ // don't allow an empty formatted line
+ size_t firstText = formattedLine.find_first_not_of(" \t");
+ if (firstText == string::npos && formattedLine.length() > 0)
+ {
+ formattedLine.erase();
+ clearFormattedLineSplitPoints();
+ if (isWhiteSpace(currentChar))
+ for (size_t i = charNum + 1; i < currentLine.length() && isWhiteSpace(currentLine[i]); i++)
+ goForward(1);
+ }
+ else if (firstText > 0)
+ {
+ formattedLine.erase(0, firstText);
+ maxSemi = (maxSemi > firstText) ? (maxSemi - firstText) : 0;
+ maxAndOr = (maxAndOr > firstText) ? (maxAndOr - firstText) : 0;
+ maxComma = (maxComma > firstText) ? (maxComma - firstText) : 0;
+ maxParen = (maxParen > firstText) ? (maxParen - firstText) : 0;
+ maxWhiteSpace = (maxWhiteSpace > firstText) ? (maxWhiteSpace - firstText) : 0;
+ }
+ // reset formattedLineCommentNum
+ if (formattedLineCommentNum != string::npos)
+ {
+ formattedLineCommentNum = formattedLine.find("//");
+ if (formattedLineCommentNum == string::npos)
+ formattedLineCommentNum = formattedLine.find("/*");
+ }
+ }
+ }
+}
+
+size_t ASFormatter::findFormattedLineSplitPoint() const
+{
+ assert(maxCodeLength != string::npos);
+ // determine where to split
+ size_t minCodeLength = 10;
+ size_t splitPoint = 0;
+ splitPoint = maxSemi;
+ if (maxAndOr >= minCodeLength)
+ splitPoint = maxAndOr;
+ if (splitPoint < minCodeLength)
+ {
+ splitPoint = maxWhiteSpace;
+ // use maxParen instead if it is long enough
+ if (maxParen > splitPoint
+ || maxParen >= maxCodeLength * .7)
+ splitPoint = maxParen;
+ // use maxComma instead if it is long enough
+ // increasing the multiplier causes more splits at whitespace
+ if (maxComma > splitPoint
+ || maxComma >= maxCodeLength * .3)
+ splitPoint = maxComma;
+ }
+ // replace split point with first available break point
+ if (splitPoint < minCodeLength)
+ {
+ splitPoint = string::npos;
+ if (maxSemiPending > 0 && maxSemiPending < splitPoint)
+ splitPoint = maxSemiPending;
+ if (maxAndOrPending > 0 && maxAndOrPending < splitPoint)
+ splitPoint = maxAndOrPending;
+ if (maxCommaPending > 0 && maxCommaPending < splitPoint)
+ splitPoint = maxCommaPending;
+ if (maxParenPending > 0 && maxParenPending < splitPoint)
+ splitPoint = maxParenPending;
+ if (maxWhiteSpacePending > 0 && maxWhiteSpacePending < splitPoint)
+ splitPoint = maxWhiteSpacePending;
+ if (splitPoint == string::npos)
+ splitPoint = 0;
+ }
+ // if remaining line after split is too long
+ else if (formattedLine.length() - splitPoint > maxCodeLength)
+ {
+ // if end of the currentLine, find a new split point
+ size_t newCharNum;
+ if (isCharPotentialHeader(currentLine, charNum))
+ newCharNum = getCurrentWord(currentLine, charNum).length() + charNum;
+ else
+ newCharNum = charNum + 2;
+ if (newCharNum + 1 > currentLine.length())
+ {
+ // don't move splitPoint from before a conditional to after
+ if (maxWhiteSpace > splitPoint + 3)
+ splitPoint = maxWhiteSpace;
+ if (maxParen > splitPoint)
+ splitPoint = maxParen;
+ }
+ }
+
+ return splitPoint;
+}
+
+void ASFormatter::clearFormattedLineSplitPoints()
+{
+ maxSemi = 0;
+ maxAndOr = 0;
+ maxComma = 0;
+ maxParen = 0;
+ maxWhiteSpace = 0;
+ maxSemiPending = 0;
+ maxAndOrPending = 0;
+ maxCommaPending = 0;
+ maxParenPending = 0;
+ maxWhiteSpacePending = 0;
+}
+
+/**
+ * Check if a pointer symbol (->) follows on the currentLine.
+ */
+bool ASFormatter::pointerSymbolFollows() const
+{
+ size_t peekNum = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (peekNum == string::npos || currentLine.compare(peekNum, 2, "->") != 0)
+ return false;
+ return true;
+}
+
+/**
+ * Compute the input checksum.
+ * This is called as an assert so it for is debug config only
+ */
+bool ASFormatter::computeChecksumIn(const string& currentLine_)
+{
+ for (size_t i = 0; i < currentLine_.length(); i++)
+ if (!isWhiteSpace(currentLine_[i]))
+ checksumIn += currentLine_[i];
+ return true;
+}
+
+/**
+ * Adjust the input checksum for deleted chars.
+ * This is called as an assert so it for is debug config only
+ */
+bool ASFormatter::adjustChecksumIn(int adjustment)
+{
+ checksumIn += adjustment;
+ return true;
+}
+
+/**
+ * get the value of checksumIn for unit testing
+ *
+ * @return checksumIn.
+ */
+size_t ASFormatter::getChecksumIn() const
+{
+ return checksumIn;
+}
+
+/**
+ * Compute the output checksum.
+ * This is called as an assert so it is for debug config only
+ */
+bool ASFormatter::computeChecksumOut(const string& beautifiedLine)
+{
+ for (size_t i = 0; i < beautifiedLine.length(); i++)
+ if (!isWhiteSpace(beautifiedLine[i]))
+ checksumOut += beautifiedLine[i];
+ return true;
+}
+
+/**
+ * Return isLineReady for the final check at end of file.
+ */
+bool ASFormatter::getIsLineReady() const
+{
+ return isLineReady;
+}
+
+/**
+ * get the value of checksumOut for unit testing
+ *
+ * @return checksumOut.
+ */
+size_t ASFormatter::getChecksumOut() const
+{
+ return checksumOut;
+}
+
+/**
+ * Return the difference in checksums.
+ * If zero all is okay.
+ */
+int ASFormatter::getChecksumDiff() const
+{
+ return checksumOut - checksumIn;
+}
+
+// for unit testing
+int ASFormatter::getFormatterFileType() const
+{
+ return formatterFileType;
+}
+
+// Check if an operator follows the next word.
+// The next word must be a legal name.
+const string* ASFormatter::getFollowingOperator() const
+{
+ // find next word
+ size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (nextNum == string::npos)
+ return nullptr;
+
+ if (!isLegalNameChar(currentLine[nextNum]))
+ return nullptr;
+
+ // bypass next word and following spaces
+ while (nextNum < currentLine.length())
+ {
+ if (!isLegalNameChar(currentLine[nextNum])
+ && !isWhiteSpace(currentLine[nextNum]))
+ break;
+ nextNum++;
+ }
+
+ if (nextNum >= currentLine.length()
+ || !isCharPotentialOperator(currentLine[nextNum])
+ || currentLine[nextNum] == '/') // comment
+ return nullptr;
+
+ const string* newOperator = ASBase::findOperator(currentLine, nextNum, operators);
+ return newOperator;
+}
+
+// Check following data to determine if the current character is an array operator.
+bool ASFormatter::isArrayOperator() const
+{
+ assert(currentChar == '*' || currentChar == '&' || currentChar == '^');
+ assert(isBraceType(braceTypeStack->back(), ARRAY_TYPE));
+
+ // find next word
+ size_t nextNum = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (nextNum == string::npos)
+ return false;
+
+ if (!isLegalNameChar(currentLine[nextNum]))
+ return false;
+
+ // bypass next word and following spaces
+ while (nextNum < currentLine.length())
+ {
+ if (!isLegalNameChar(currentLine[nextNum])
+ && !isWhiteSpace(currentLine[nextNum]))
+ break;
+ nextNum++;
+ }
+
+ // check for characters that indicate an operator
+ if (currentLine[nextNum] == ','
+ || currentLine[nextNum] == '}'
+ || currentLine[nextNum] == ')'
+ || currentLine[nextNum] == '(')
+ return true;
+ return false;
+}
+
+// Reset the flags that indicate various statement information.
+void ASFormatter::resetEndOfStatement()
+{
+ foundQuestionMark = false;
+ foundNamespaceHeader = false;
+ foundClassHeader = false;
+ foundStructHeader = false;
+ foundInterfaceHeader = false;
+ foundPreDefinitionHeader = false;
+ foundPreCommandHeader = false;
+ foundPreCommandMacro = false;
+ foundTrailingReturnType = false;
+ foundCastOperator = false;
+ isInPotentialCalculation = false;
+ isSharpAccessor = false;
+ isSharpDelegate = false;
+ isInObjCMethodDefinition = false;
+ isInObjCInterface = false;
+ isInObjCSelector = false;
+ isInEnum = false;
+ isInExternC = false;
+ elseHeaderFollowsComments = false;
+ nonInStatementBrace = 0;
+ while (!questionMarkStack->empty())
+ questionMarkStack->pop_back();
+}
+
+// Find the colon alignment for Objective-C method definitions and method calls.
+int ASFormatter::findObjCColonAlignment() const
+{
+ assert(currentChar == '+' || currentChar == '-' || currentChar == '[');
+ assert(getAlignMethodColon());
+
+ bool isFirstLine = true;
+ bool haveFirstColon = false;
+ bool foundMethodColon = false;
+ bool isInComment_ = false;
+ bool isInQuote_ = false;
+ char quoteChar_ = ' ';
+ int sqBracketCount = 0;
+ int colonAdjust = 0;
+ int colonAlign = 0;
+ string nextLine_ = currentLine;
+ ASPeekStream stream(sourceIterator);
+
+ // peek next line
+ while (sourceIterator->hasMoreLines() || isFirstLine)
+ {
+ if (!isFirstLine)
+ nextLine_ = stream.peekNextLine();
+ // parse the line
+ haveFirstColon = false;
+ nextLine_ = ASBeautifier::trim(nextLine_);
+ for (size_t i = 0; i < nextLine_.length(); i++)
+ {
+ if (isWhiteSpace(nextLine_[i]))
+ continue;
+ if (nextLine_.compare(i, 2, "/*") == 0)
+ isInComment_ = true;
+ if (isInComment_)
+ {
+ if (nextLine_.compare(i, 2, "*/") == 0)
+ {
+ isInComment_ = false;
+ ++i;
+ }
+ continue;
+ }
+ if (nextLine_[i] == '\\')
+ {
+ ++i;
+ continue;
+ }
+ if (isInQuote_)
+ {
+ if (nextLine_[i] == quoteChar_)
+ isInQuote_ = false;
+ continue;
+ }
+
+ if (nextLine_[i] == '"'
+ || (nextLine_[i] == '\'' && !isDigitSeparator(nextLine_, i)))
+ {
+ isInQuote_ = true;
+ quoteChar_ = nextLine_[i];
+ continue;
+ }
+ if (nextLine_.compare(i, 2, "//") == 0)
+ {
+ i = nextLine_.length();
+ continue;
+ }
+ // process the current char
+ if ((nextLine_[i] == '{' && (currentChar == '-' || currentChar == '+'))
+ || nextLine_[i] == ';')
+ goto EndOfWhileLoop; // end of method definition
+ if (nextLine_[i] == ']')
+ {
+ --sqBracketCount;
+ if (sqBracketCount == 0)
+ goto EndOfWhileLoop; // end of method call
+ }
+ if (nextLine_[i] == '[')
+ ++sqBracketCount;
+ if (isFirstLine) // colon align does not include the first line
+ continue;
+ if (sqBracketCount > 1)
+ continue;
+ if (haveFirstColon) // multiple colons per line
+ continue;
+ // compute colon adjustment
+ if (nextLine_[i] == ':')
+ {
+ haveFirstColon = true;
+ foundMethodColon = true;
+ if (shouldPadMethodColon)
+ {
+ int spacesStart;
+ for (spacesStart = i; spacesStart > 0; spacesStart--)
+ if (!isWhiteSpace(nextLine_[spacesStart - 1]))
+ break;
+ int spaces = i - spacesStart;
+ if (objCColonPadMode == COLON_PAD_ALL || objCColonPadMode == COLON_PAD_BEFORE)
+ colonAdjust = 1 - spaces;
+ else if (objCColonPadMode == COLON_PAD_NONE || objCColonPadMode == COLON_PAD_AFTER)
+ colonAdjust = 0 - spaces;
+ }
+ // compute alignment
+ int colonPosition = i + colonAdjust;
+ if (colonPosition > colonAlign)
+ colonAlign = colonPosition;
+ }
+ } // end of for loop
+ isFirstLine = false;
+ } // end of while loop
+EndOfWhileLoop:
+ if (!foundMethodColon)
+ colonAlign = -1;
+ return colonAlign;
+}
+
+// pad an Objective-C method colon
+void ASFormatter::padObjCMethodColon()
+{
+ assert(currentChar == ':');
+ int commentAdjust = 0;
+ char nextChar = peekNextChar();
+ if (objCColonPadMode == COLON_PAD_NONE
+ || objCColonPadMode == COLON_PAD_AFTER
+ || nextChar == ')')
+ {
+ // remove spaces before
+ for (int i = formattedLine.length() - 1; (i > -1) && isWhiteSpace(formattedLine[i]); i--)
+ {
+ formattedLine.erase(i);
+ --commentAdjust;
+ }
+ }
+ else
+ {
+ // pad space before
+ for (int i = formattedLine.length() - 1; (i > 0) && isWhiteSpace(formattedLine[i]); i--)
+ if (isWhiteSpace(formattedLine[i - 1]))
+ {
+ formattedLine.erase(i);
+ --commentAdjust;
+ }
+ appendSpacePad();
+ }
+ if (objCColonPadMode == COLON_PAD_NONE
+ || objCColonPadMode == COLON_PAD_BEFORE
+ || nextChar == ')')
+ {
+ // remove spaces after
+ int nextText = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (nextText == (int)string::npos)
+ nextText = currentLine.length();
+ int spaces = nextText - charNum - 1;
+ if (spaces > 0)
+ {
+ // do not use goForward here
+ currentLine.erase(charNum + 1, spaces);
+ spacePadNum -= spaces;
+ }
+ }
+ else
+ {
+ // pad space after
+ int nextText = currentLine.find_first_not_of(" \t", charNum + 1);
+ if (nextText == (int)string::npos)
+ nextText = currentLine.length();
+ int spaces = nextText - charNum - 1;
+ if (spaces == 0)
+ {
+ currentLine.insert(charNum + 1, 1, ' ');
+ spacePadNum += 1;
+ }
+ else if (spaces > 1)
+ {
+ // do not use goForward here
+ currentLine.erase(charNum + 1, spaces - 1);
+ spacePadNum -= spaces - 1;
+ }
+ }
+ spacePadNum += commentAdjust;
+}
+
+// Remove the leading '*' from a comment line and indent to the next tab.
+void ASFormatter::stripCommentPrefix()
+{
+ int firstChar = formattedLine.find_first_not_of(" \t");
+ if (firstChar < 0)
+ return;
+
+ if (isInCommentStartLine)
+ {
+ // comment opener must begin the line
+ if (formattedLine.compare(firstChar, 2, "/*") != 0)
+ return;
+ int commentOpener = firstChar;
+ // ignore single line comments
+ int commentEnd = formattedLine.find("*/", firstChar + 2);
+ if (commentEnd != -1)
+ return;
+ // first char after the comment opener must be at least one indent
+ int followingText = formattedLine.find_first_not_of(" \t", commentOpener + 2);
+ if (followingText < 0)
+ return;
+ if (formattedLine[followingText] == '*' || formattedLine[followingText] == '!')
+ followingText = formattedLine.find_first_not_of(" \t", followingText + 1);
+ if (followingText < 0)
+ return;
+ if (formattedLine[followingText] == '*')
+ return;
+ int indentLen = getIndentLength();
+ int followingTextIndent = followingText - commentOpener;
+ if (followingTextIndent < indentLen)
+ {
+ string stringToInsert(indentLen - followingTextIndent, ' ');
+ formattedLine.insert(followingText, stringToInsert);
+ }
+ return;
+ }
+ // comment body including the closer
+ if (formattedLine[firstChar] == '*')
+ {
+ if (formattedLine.compare(firstChar, 2, "*/") == 0)
+ {
+ // line starts with an end comment
+ formattedLine = "*/";
+ }
+ else
+ {
+ // build a new line with one indent
+ int secondChar = formattedLine.find_first_not_of(" \t", firstChar + 1);
+ if (secondChar < 0)
+ {
+ adjustChecksumIn(-'*');
+ formattedLine.erase();
+ return;
+ }
+ if (formattedLine[secondChar] == '*')
+ return;
+ // replace the leading '*'
+ int indentLen = getIndentLength();
+ adjustChecksumIn(-'*');
+ // second char must be at least one indent
+ if (formattedLine.substr(0, secondChar).find('\t') != string::npos)
+ {
+ formattedLine.erase(firstChar, 1);
+ }
+ else
+ {
+ int spacesToInsert = 0;
+ if (secondChar >= indentLen)
+ spacesToInsert = secondChar;
+ else
+ spacesToInsert = indentLen;
+ formattedLine = string(spacesToInsert, ' ') + formattedLine.substr(secondChar);
+ }
+ // remove a trailing '*'
+ int lastChar = formattedLine.find_last_not_of(" \t");
+ if (lastChar > -1 && formattedLine[lastChar] == '*')
+ {
+ adjustChecksumIn(-'*');
+ formattedLine[lastChar] = ' ';
+ }
+ }
+ }
+ else
+ {
+ // first char not a '*'
+ // first char must be at least one indent
+ if (formattedLine.substr(0, firstChar).find('\t') == string::npos)
+ {
+ int indentLen = getIndentLength();
+ if (firstChar < indentLen)
+ {
+ string stringToInsert(indentLen, ' ');
+ formattedLine = stringToInsert + formattedLine.substr(firstChar);
+ }
+ }
+ }
+}
+
+} // end namespace astyle
--- /dev/null
+// ASLocalizer.cpp
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+//
+// File encoding for this file is UTF-8 WITHOUT a byte order mark (BOM).
+// русский 中文(简体) 日本語 한국의
+//
+// Windows:
+// Add the required "Language" to the system.
+// The settings do NOT need to be changed to the added language.
+// Change the "Region" settings.
+// Change both the "Format" and the "Current Language..." settings.
+// A restart is required if the codepage has changed.
+// Windows problems:
+// Hindi - no available locale, language pack removed
+// Japanese - language pack install error
+// Ukranian - displays a ? instead of i
+//
+// Linux:
+// Change the LANG environment variable: LANG=fr_FR.UTF-8.
+// setlocale() will use the LANG environment variable on Linux.
+//
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * To add a new language to this source module:
+ *
+ * Add a new translation class to ASLocalizer.h.
+ * Update the WinLangCode array in ASLocalizer.cpp.
+ * Add the language code to setTranslationClass() in ASLocalizer.cpp.
+ * Add the English-Translation pair to the constructor in ASLocalizer.cpp.
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ */
+
+//----------------------------------------------------------------------------
+// headers
+//----------------------------------------------------------------------------
+
+#include "ASLocalizer.h"
+
+#ifdef _WIN32
+ #include <windows.h>
+#endif
+
+#ifdef __VMS
+ #define __USE_STD_IOSTREAM 1
+ #include <assert>
+#else
+ #include <cassert>
+#endif
+
+#include <cstdio>
+#include <iostream>
+#include <clocale> // needed by some compilers
+#include <cstdlib>
+#include <typeinfo>
+
+#ifdef _MSC_VER
+ #pragma warning(disable: 4996) // secure version deprecation warnings
+#endif
+
+#ifdef __BORLANDC__
+ #pragma warn -8104 // Local Static with constructor dangerous for multi-threaded apps
+#endif
+
+#ifdef __INTEL_COMPILER
+ #pragma warning(disable: 383) // value copied to temporary, reference to temporary used
+ #pragma warning(disable: 981) // operands are evaluated in unspecified order
+#endif
+
+#ifdef __clang__
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations" // wcstombs
+#endif
+
+namespace astyle {
+
+#ifndef ASTYLE_LIB
+
+//----------------------------------------------------------------------------
+// ASLocalizer class methods.
+//----------------------------------------------------------------------------
+
+ASLocalizer::ASLocalizer()
+// Set the locale information.
+{
+ // set language default values to english (ascii)
+ // this will be used if a locale or a language cannot be found
+ m_localeName = "UNKNOWN";
+ m_langID = "en";
+ m_lcid = 0;
+ m_subLangID.clear();
+ m_translation = nullptr;
+
+ // Not all compilers support the C++ function locale::global(locale(""));
+ char* localeName = setlocale(LC_ALL, "");
+ if (localeName == nullptr) // use the english (ascii) defaults
+ {
+ fprintf(stderr, "\n%s\n\n", "Cannot set native locale, reverting to English");
+ setTranslationClass();
+ return;
+ }
+ // set the class variables
+#ifdef _WIN32
+ size_t lcid = GetUserDefaultLCID();
+ setLanguageFromLCID(lcid);
+#else
+ setLanguageFromName(localeName);
+#endif
+}
+
+ASLocalizer::~ASLocalizer()
+// Delete dynamically allocated memory.
+{
+ delete m_translation;
+}
+
+#ifdef _WIN32
+
+struct WinLangCode
+{
+ size_t winLang;
+ char canonicalLang[3];
+};
+
+static WinLangCode wlc[] =
+// primary language identifier http://msdn.microsoft.com/en-us/library/aa912554.aspx
+// sublanguage identifier http://msdn.microsoft.com/en-us/library/aa913256.aspx
+// language ID http://msdn.microsoft.com/en-us/library/ee797784%28v=cs.20%29.aspx
+{
+ { LANG_BULGARIAN, "bg" }, // bg-BG 1251
+ { LANG_CHINESE, "zh" }, // zh-CHS, zh-CHT
+ { LANG_DUTCH, "nl" }, // nl-NL 1252
+ { LANG_ENGLISH, "en" }, // en-US 1252
+ { LANG_ESTONIAN, "et" }, // et-EE
+ { LANG_FINNISH, "fi" }, // fi-FI 1252
+ { LANG_FRENCH, "fr" }, // fr-FR 1252
+ { LANG_GERMAN, "de" }, // de-DE 1252
+ { LANG_GREEK, "el" }, // el-GR 1253
+ { LANG_HINDI, "hi" }, // hi-IN
+ { LANG_HUNGARIAN, "hu" }, // hu-HU 1250
+ { LANG_ITALIAN, "it" }, // it-IT 1252
+ { LANG_JAPANESE, "ja" }, // ja-JP
+ { LANG_KOREAN, "ko" }, // ko-KR
+ { LANG_NORWEGIAN, "nn" }, // nn-NO 1252
+ { LANG_POLISH, "pl" }, // pl-PL 1250
+ { LANG_PORTUGUESE, "pt" }, // pt-PT 1252
+ { LANG_ROMANIAN, "ro" }, // ro-RO 1250
+ { LANG_RUSSIAN, "ru" }, // ru-RU 1251
+ { LANG_SPANISH, "es" }, // es-ES 1252
+ { LANG_SWEDISH, "sv" }, // sv-SE 1252
+ { LANG_UKRAINIAN, "uk" }, // uk-UA 1251
+};
+
+void ASLocalizer::setLanguageFromLCID(size_t lcid)
+// Windows get the language to use from the user locale.
+// NOTE: GetUserDefaultLocaleName() gets nearly the same name as Linux.
+// But it needs Windows Vista or higher.
+// Same with LCIDToLocaleName().
+{
+ m_lcid = lcid;
+ m_langID = "en"; // default to english
+
+ size_t lang = PRIMARYLANGID(LANGIDFROMLCID(m_lcid));
+ size_t sublang = SUBLANGID(LANGIDFROMLCID(m_lcid));
+ // find language in the wlc table
+ size_t count = sizeof(wlc) / sizeof(wlc[0]);
+ for (size_t i = 0; i < count; i++)
+ {
+ if (wlc[i].winLang == lang)
+ {
+ m_langID = wlc[i].canonicalLang;
+ break;
+ }
+ }
+ if (m_langID == "zh")
+ {
+ if (sublang == SUBLANG_CHINESE_SIMPLIFIED || sublang == SUBLANG_CHINESE_SINGAPORE)
+ m_subLangID = "CHS";
+ else
+ m_subLangID = "CHT"; // default
+ }
+ setTranslationClass();
+}
+
+#endif // _win32
+
+string ASLocalizer::getLanguageID() const
+// Returns the language ID in m_langID.
+{
+ return m_langID;
+}
+
+const Translation* ASLocalizer::getTranslationClass() const
+// Returns the name of the translation class in m_translation. Used for testing.
+{
+ assert(m_translation);
+ return m_translation;
+}
+
+void ASLocalizer::setLanguageFromName(const char* langID)
+// Linux set the language to use from the langID.
+//
+// the language string has the following form
+//
+// lang[_LANG][.encoding][@modifier]
+//
+// (see environ(5) in the Open Unix specification)
+//
+// where lang is the primary language, LANG is a sublang/territory,
+// encoding is the charset to use and modifier "allows the user to select
+// a specific instance of localization data within a single category"
+//
+// for example, the following strings are valid:
+// fr
+// fr_FR
+// de_DE.iso88591
+// de_DE@euro
+// de_DE.iso88591@euro
+{
+ // the constants describing the format of lang_LANG locale string
+ m_lcid = 0;
+ string langStr = langID;
+ m_langID = langStr.substr(0, 2);
+
+ // need the sublang for chinese
+ if (m_langID == "zh" && langStr[2] == '_')
+ {
+ string subLang = langStr.substr(3, 2);
+ if (subLang == "CN" || subLang == "SG")
+ m_subLangID = "CHS";
+ else
+ m_subLangID = "CHT"; // default
+ }
+ setTranslationClass();
+}
+
+const char* ASLocalizer::settext(const char* textIn) const
+// Call the settext class and return the value.
+{
+ assert(m_translation);
+ const string stringIn = textIn;
+ return m_translation->translate(stringIn).c_str();
+}
+
+void ASLocalizer::setTranslationClass()
+// Return the required translation class.
+// Sets the class variable m_translation from the value of m_langID.
+// Get the language ID at http://msdn.microsoft.com/en-us/library/ee797784%28v=cs.20%29.aspx
+{
+ assert(m_langID.length());
+ // delete previously set (--ascii option)
+ if (m_translation != nullptr)
+ {
+ delete m_translation;
+ m_translation = nullptr;
+ }
+ if (m_langID == "bg")
+ m_translation = new Bulgarian;
+ else if (m_langID == "zh" && m_subLangID == "CHS")
+ m_translation = new ChineseSimplified;
+ else if (m_langID == "zh" && m_subLangID == "CHT")
+ m_translation = new ChineseTraditional;
+ else if (m_langID == "nl")
+ m_translation = new Dutch;
+ else if (m_langID == "en")
+ m_translation = new English;
+ else if (m_langID == "et")
+ m_translation = new Estonian;
+ else if (m_langID == "fi")
+ m_translation = new Finnish;
+ else if (m_langID == "fr")
+ m_translation = new French;
+ else if (m_langID == "de")
+ m_translation = new German;
+ else if (m_langID == "el")
+ m_translation = new Greek;
+ else if (m_langID == "hi")
+ m_translation = new Hindi;
+ else if (m_langID == "hu")
+ m_translation = new Hungarian;
+ else if (m_langID == "it")
+ m_translation = new Italian;
+ else if (m_langID == "ja")
+ m_translation = new Japanese;
+ else if (m_langID == "ko")
+ m_translation = new Korean;
+ else if (m_langID == "nn")
+ m_translation = new Norwegian;
+ else if (m_langID == "pl")
+ m_translation = new Polish;
+ else if (m_langID == "pt")
+ m_translation = new Portuguese;
+ else if (m_langID == "ro")
+ m_translation = new Romanian;
+ else if (m_langID == "ru")
+ m_translation = new Russian;
+ else if (m_langID == "es")
+ m_translation = new Spanish;
+ else if (m_langID == "sv")
+ m_translation = new Swedish;
+ else if (m_langID == "uk")
+ m_translation = new Ukrainian;
+ else // default
+ m_translation = new English;
+}
+
+//----------------------------------------------------------------------------
+// Translation base class methods.
+//----------------------------------------------------------------------------
+
+void Translation::addPair(const string& english, const wstring& translated)
+// Add a string pair to the translation vector.
+{
+ pair<string, wstring> entry(english, translated);
+ m_translation.emplace_back(entry);
+}
+
+string Translation::convertToMultiByte(const wstring& wideStr) const
+// Convert wchar_t to a multibyte string using the currently assigned locale.
+// Return an empty string if an error occurs.
+{
+ static bool msgDisplayed = false;
+ // get length of the output excluding the nullptr and validate the parameters
+ size_t mbLen = wcstombs(nullptr, wideStr.c_str(), 0);
+ if (mbLen == string::npos)
+ {
+ if (!msgDisplayed)
+ {
+ fprintf(stderr, "\n%s\n\n", "Cannot convert to multi-byte string, reverting to English");
+ msgDisplayed = true;
+ }
+ return "";
+ }
+ // convert the characters
+ char* mbStr = new (nothrow) char[mbLen + 1];
+ if (mbStr == nullptr)
+ {
+ if (!msgDisplayed)
+ {
+ fprintf(stderr, "\n%s\n\n", "Bad memory alloc for multi-byte string, reverting to English");
+ msgDisplayed = true;
+ }
+ return "";
+ }
+ wcstombs(mbStr, wideStr.c_str(), mbLen + 1);
+ // return the string
+ string mbTranslation = mbStr;
+ delete[] mbStr;
+ return mbTranslation;
+}
+
+size_t Translation::getTranslationVectorSize() const
+// Return the translation vector size. Used for testing.
+{
+ return m_translation.size();
+}
+
+bool Translation::getWideTranslation(const string& stringIn, wstring& wideOut) const
+// Get the wide translation string. Used for testing.
+{
+ for (size_t i = 0; i < m_translation.size(); i++)
+ {
+ if (m_translation[i].first == stringIn)
+ {
+ wideOut = m_translation[i].second;
+ return true;
+ }
+ }
+ // not found
+ wideOut = L"";
+ return false;
+}
+
+string& Translation::translate(const string& stringIn) const
+// Translate a string.
+// Return a mutable string so the method can have a "const" designation.
+// This allows "settext" to be called from a "const" method.
+{
+ m_mbTranslation.clear();
+ for (size_t i = 0; i < m_translation.size(); i++)
+ {
+ if (m_translation[i].first == stringIn)
+ {
+ m_mbTranslation = convertToMultiByte(m_translation[i].second);
+ break;
+ }
+ }
+ // not found, return english
+ if (m_mbTranslation.empty())
+ m_mbTranslation = stringIn;
+ return m_mbTranslation;
+}
+
+//----------------------------------------------------------------------------
+// Translation class methods.
+// These classes have only a constructor which builds the language vector.
+//----------------------------------------------------------------------------
+
+Bulgarian::Bulgarian() // български
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Форматиран %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Непроменен %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"директория %s\n");
+ addPair("Exclude %s\n", L"Изключвам %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Изключване (несравнимо) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s форматиран %s hепроменен ");
+ addPair(" seconds ", L" секунди ");
+ addPair("%d min %d sec ", L"%d мин %d сек ");
+ addPair("%s lines\n", L"%s линии\n");
+ addPair("Using default options file %s\n", L"Използване на файла възможности по подразбиране %s\n");
+ addPair("Opening HTML documentation %s\n", L"Откриване HTML документация %s\n");
+ addPair("Invalid option file options:", L"Невалидни опции опция файлове:");
+ addPair("Invalid command line options:", L"Невалидни опции за командния ред:");
+ addPair("For help on options type 'astyle -h'", L"За помощ относно възможностите тип 'astyle -h'");
+ addPair("Cannot open options file", L"Не може да се отвори файл опции");
+ addPair("Cannot open directory", L"Не може да се отвори директория");
+ addPair("Cannot open HTML file %s\n", L"Не може да се отвори HTML файл %s\n");
+ addPair("Command execute failure", L"Command изпълни недостатъчност");
+ addPair("Command is not installed", L"Command не е инсталиран");
+ addPair("Missing filename in %s\n", L"Липсва името на файла в %s\n");
+ addPair("Recursive option with no wildcard", L"Рекурсивно опция, без маска");
+ addPair("Did you intend quote the filename", L"Знаете ли намерение да цитирам името на файла");
+ addPair("No file to process %s\n", L"Не файл за обработка %s\n");
+ addPair("Did you intend to use --recursive", L"Знаете ли възнамерявате да използвате --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Не може да са UTF-32 кодиране");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style е прекратено");
+}
+
+ChineseSimplified::ChineseSimplified() // 中文(简体)
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"格式化 %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"未改变 %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"目录 %s\n");
+ addPair("Exclude %s\n", L"排除 %s\n");
+ addPair("Exclude (unmatched) %s\n", L"排除(无匹配项) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s 格式化 %s 未改变 ");
+ addPair(" seconds ", L" 秒 ");
+ addPair("%d min %d sec ", L"%d 分 %d 秒 ");
+ addPair("%s lines\n", L"%s 行\n");
+ addPair("Using default options file %s\n", L"使用默认配置文件 %s\n");
+ addPair("Opening HTML documentation %s\n", L"打开HTML文档 %s\n");
+ addPair("Invalid option file options:", L"无效的配置文件选项:");
+ addPair("Invalid command line options:", L"无效的命令行选项:");
+ addPair("For help on options type 'astyle -h'", L"输入 'astyle -h' 以获得有关命令行的帮助");
+ addPair("Cannot open options file", L"无法打开配置文件");
+ addPair("Cannot open directory", L"无法打开目录");
+ addPair("Cannot open HTML file %s\n", L"无法打开HTML文件 %s\n");
+ addPair("Command execute failure", L"执行命令失败");
+ addPair("Command is not installed", L"未安装命令");
+ addPair("Missing filename in %s\n", L"在%s缺少文件名\n");
+ addPair("Recursive option with no wildcard", L"递归选项没有通配符");
+ addPair("Did you intend quote the filename", L"你打算引用文件名");
+ addPair("No file to process %s\n", L"没有文件可处理 %s\n");
+ addPair("Did you intend to use --recursive", L"你打算使用 --recursive");
+ addPair("Cannot process UTF-32 encoding", L"不能处理UTF-32编码");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style 已经终止运行");
+}
+
+ChineseTraditional::ChineseTraditional() // 中文(繁體)
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"格式化 %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"未改變 %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"目錄 %s\n");
+ addPair("Exclude %s\n", L"排除 %s\n");
+ addPair("Exclude (unmatched) %s\n", L"排除(無匹配項) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s 格式化 %s 未改變 ");
+ addPair(" seconds ", L" 秒 ");
+ addPair("%d min %d sec ", L"%d 分 %d 秒 ");
+ addPair("%s lines\n", L"%s 行\n");
+ addPair("Using default options file %s\n", L"使用默認配置文件 %s\n");
+ addPair("Opening HTML documentation %s\n", L"打開HTML文檔 %s\n");
+ addPair("Invalid option file options:", L"無效的配置文件選項:");
+ addPair("Invalid command line options:", L"無效的命令行選項:");
+ addPair("For help on options type 'astyle -h'", L"輸入'astyle -h'以獲得有關命令行的幫助:");
+ addPair("Cannot open options file", L"無法打開配置文件");
+ addPair("Cannot open directory", L"無法打開目錄");
+ addPair("Cannot open HTML file %s\n", L"無法打開HTML文件 %s\n");
+ addPair("Command execute failure", L"執行命令失敗");
+ addPair("Command is not installed", L"未安裝命令");
+ addPair("Missing filename in %s\n", L"在%s缺少文件名\n");
+ addPair("Recursive option with no wildcard", L"遞歸選項沒有通配符");
+ addPair("Did you intend quote the filename", L"你打算引用文件名");
+ addPair("No file to process %s\n", L"沒有文件可處理 %s\n");
+ addPair("Did you intend to use --recursive", L"你打算使用 --recursive");
+ addPair("Cannot process UTF-32 encoding", L"不能處理UTF-32編碼");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style 已經終止運行");
+}
+
+Dutch::Dutch() // Nederlandse
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Geformatteerd %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Onveranderd %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Directory %s\n");
+ addPair("Exclude %s\n", L"Uitsluiten %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Uitgesloten (ongeëvenaarde) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s geformatteerd %s onveranderd ");
+ addPair(" seconds ", L" seconden ");
+ addPair("%d min %d sec ", L"%d min %d sec ");
+ addPair("%s lines\n", L"%s lijnen\n");
+ addPair("Using default options file %s\n", L"Met behulp van standaard opties bestand %s\n");
+ addPair("Opening HTML documentation %s\n", L"Het openen van HTML-documentatie %s\n");
+ addPair("Invalid option file options:", L"Ongeldige optie file opties:");
+ addPair("Invalid command line options:", L"Ongeldige command line opties:");
+ addPair("For help on options type 'astyle -h'", L"Voor hulp bij 'astyle-h' opties het type");
+ addPair("Cannot open options file", L"Kan niet worden geopend options bestand");
+ addPair("Cannot open directory", L"Kan niet open directory");
+ addPair("Cannot open HTML file %s\n", L"Kan HTML-bestand niet openen %s\n");
+ addPair("Command execute failure", L"Voeren commando falen");
+ addPair("Command is not installed", L"Command is niet geïnstalleerd");
+ addPair("Missing filename in %s\n", L"Ontbrekende bestandsnaam in %s\n");
+ addPair("Recursive option with no wildcard", L"Recursieve optie met geen wildcard");
+ addPair("Did you intend quote the filename", L"Heeft u van plan citaat van de bestandsnaam");
+ addPair("No file to process %s\n", L"Geen bestand te verwerken %s\n");
+ addPair("Did you intend to use --recursive", L"Hebt u van plan bent te gebruiken --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Kan niet verwerken UTF-32 codering");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style heeft beëindigd");
+}
+
+English::English()
+// this class is NOT translated
+{}
+
+Estonian::Estonian() // Eesti
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formaadis %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Muutumatu %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Kataloog %s\n");
+ addPair("Exclude %s\n", L"Välista %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Välista (tasakaalustamata) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formaadis %s muutumatu ");
+ addPair(" seconds ", L" sekundit ");
+ addPair("%d min %d sec ", L"%d min %d sek ");
+ addPair("%s lines\n", L"%s read\n");
+ addPair("Using default options file %s\n", L"Kasutades selliseid vaikimisi valikuid faili %s\n");
+ addPair("Opening HTML documentation %s\n", L"Avamine HTML dokumentatsioon %s\n");
+ addPair("Invalid option file options:", L"Vale valik faili võimalusi:");
+ addPair("Invalid command line options:", L"Vale käsureavõtmetega:");
+ addPair("For help on options type 'astyle -h'", L"Abiks võimaluste tüüp 'astyle -h'");
+ addPair("Cannot open options file", L"Ei saa avada võimalusi faili");
+ addPair("Cannot open directory", L"Ei saa avada kataloogi");
+ addPair("Cannot open HTML file %s\n", L"Ei saa avada HTML-faili %s\n");
+ addPair("Command execute failure", L"Käsk täita rike");
+ addPair("Command is not installed", L"Käsk ei ole paigaldatud");
+ addPair("Missing filename in %s\n", L"Kadunud failinimi %s\n");
+ addPair("Recursive option with no wildcard", L"Rekursiivne võimalus ilma metamärgi");
+ addPair("Did you intend quote the filename", L"Kas te kavatsete tsiteerida failinimi");
+ addPair("No file to process %s\n", L"No faili töötlema %s\n");
+ addPair("Did you intend to use --recursive", L"Kas te kavatsete kasutada --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Ei saa töödelda UTF-32 kodeeringus");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style on lõpetatud");
+}
+
+Finnish::Finnish() // Suomeksi
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Muotoiltu %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Ennallaan %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Directory %s\n");
+ addPair("Exclude %s\n", L"Sulkea %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Sulkea (verraton) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s muotoiltu %s ennallaan ");
+ addPair(" seconds ", L" sekuntia ");
+ addPair("%d min %d sec ", L"%d min %d sek ");
+ addPair("%s lines\n", L"%s linjat\n");
+ addPair("Using default options file %s\n", L"Käyttämällä oletusasetuksia tiedosto %s\n");
+ addPair("Opening HTML documentation %s\n", L"Avaaminen HTML asiakirjat %s\n");
+ addPair("Invalid option file options:", L"Virheellinen vaihtoehto tiedosto vaihtoehtoja:");
+ addPair("Invalid command line options:", L"Virheellinen komentorivin:");
+ addPair("For help on options type 'astyle -h'", L"Apua vaihtoehdoista tyyppi 'astyle -h'");
+ addPair("Cannot open options file", L"Ei voi avata vaihtoehtoja tiedostoa");
+ addPair("Cannot open directory", L"Ei Open Directory");
+ addPair("Cannot open HTML file %s\n", L"Ei voi avata HTML-tiedoston %s\n");
+ addPair("Command execute failure", L"Suorita komento vika");
+ addPair("Command is not installed", L"Komento ei ole asennettu");
+ addPair("Missing filename in %s\n", L"Puuttuvat tiedostonimi %s\n");
+ addPair("Recursive option with no wildcard", L"Rekursiivinen vaihtoehto ilman wildcard");
+ addPair("Did you intend quote the filename", L"Oletko aio lainata tiedostonimi");
+ addPair("No file to process %s\n", L"Ei tiedostoa käsitellä %s\n");
+ addPair("Did you intend to use --recursive", L"Oliko aiot käyttää --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Ei voi käsitellä UTF-32 koodausta");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style on päättynyt");
+}
+
+French::French() // Française
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formaté %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Inchangée %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Répertoire %s\n");
+ addPair("Exclude %s\n", L"Exclure %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Exclure (non appariés) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formaté %s inchangée ");
+ addPair(" seconds ", L" seconde ");
+ addPair("%d min %d sec ", L"%d min %d sec ");
+ addPair("%s lines\n", L"%s lignes\n");
+ addPair("Using default options file %s\n", L"Options par défaut utilisation du fichier %s\n");
+ addPair("Opening HTML documentation %s\n", L"Ouverture documentation HTML %s\n");
+ addPair("Invalid option file options:", L"Options Blancs option du fichier:");
+ addPair("Invalid command line options:", L"Blancs options ligne de commande:");
+ addPair("For help on options type 'astyle -h'", L"Pour de l'aide sur les options tapez 'astyle -h'");
+ addPair("Cannot open options file", L"Impossible d'ouvrir le fichier d'options");
+ addPair("Cannot open directory", L"Impossible d'ouvrir le répertoire");
+ addPair("Cannot open HTML file %s\n", L"Impossible d'ouvrir le fichier HTML %s\n");
+ addPair("Command execute failure", L"Exécuter échec de la commande");
+ addPair("Command is not installed", L"Commande n'est pas installé");
+ addPair("Missing filename in %s\n", L"Nom de fichier manquant dans %s\n");
+ addPair("Recursive option with no wildcard", L"Option récursive sans joker");
+ addPair("Did you intend quote the filename", L"Avez-vous l'intention de citer le nom de fichier");
+ addPair("No file to process %s\n", L"Aucun fichier à traiter %s\n");
+ addPair("Did you intend to use --recursive", L"Avez-vous l'intention d'utiliser --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Impossible de traiter codage UTF-32");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style a mis fin");
+}
+
+German::German() // Deutsch
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formatiert %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Unverändert %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Verzeichnis %s\n");
+ addPair("Exclude %s\n", L"Ausschließen %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Ausschließen (unerreichte) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formatiert %s unverändert ");
+ addPair(" seconds ", L" sekunden ");
+ addPair("%d min %d sec ", L"%d min %d sek ");
+ addPair("%s lines\n", L"%s linien\n");
+ addPair("Using default options file %s\n", L"Mit Standard-Optionen Dat %s\n");
+ addPair("Opening HTML documentation %s\n", L"Öffnen HTML-Dokumentation %s\n");
+ addPair("Invalid option file options:", L"Ungültige Option Datei-Optionen:");
+ addPair("Invalid command line options:", L"Ungültige Kommandozeilen-Optionen:");
+ addPair("For help on options type 'astyle -h'", L"Für Hilfe zu den Optionen geben Sie 'astyle -h'");
+ addPair("Cannot open options file", L"Kann nicht geöffnet werden Optionsdatei");
+ addPair("Cannot open directory", L"Kann nicht geöffnet werden Verzeichnis");
+ addPair("Cannot open HTML file %s\n", L"Kann nicht öffnen HTML-Datei %s\n");
+ addPair("Command execute failure", L"Execute Befehl Scheitern");
+ addPair("Command is not installed", L"Befehl ist nicht installiert");
+ addPair("Missing filename in %s\n", L"Missing in %s Dateiname\n");
+ addPair("Recursive option with no wildcard", L"Rekursive Option ohne Wildcard");
+ addPair("Did you intend quote the filename", L"Haben Sie die Absicht Inhalte der Dateiname");
+ addPair("No file to process %s\n", L"Keine Datei zu verarbeiten %s\n");
+ addPair("Did you intend to use --recursive", L"Haben Sie verwenden möchten --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Nicht verarbeiten kann UTF-32 Codierung");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style ist beendet");
+}
+
+Greek::Greek() // ελληνικά
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Διαμορφωμένη %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Αμετάβλητος %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Κατάλογος %s\n");
+ addPair("Exclude %s\n", L"Αποκλείω %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Ausschließen (unerreichte) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s σχηματοποιημένη %s αμετάβλητες ");
+ addPair(" seconds ", L" δευτερόλεπτα ");
+ addPair("%d min %d sec ", L"%d λεπ %d δευ ");
+ addPair("%s lines\n", L"%s γραμμές\n");
+ addPair("Using default options file %s\n", L"Χρησιμοποιώντας το αρχείο προεπιλεγμένες επιλογές %s\n");
+ addPair("Opening HTML documentation %s\n", L"Εγκαίνια έγγραφα HTML %s\n");
+ addPair("Invalid option file options:", L"Μη έγκυρες επιλογές αρχείου επιλογή:");
+ addPair("Invalid command line options:", L"Μη έγκυρη επιλογές γραμμής εντολών:");
+ addPair("For help on options type 'astyle -h'", L"Για βοήθεια σχετικά με το είδος επιλογές 'astyle -h'");
+ addPair("Cannot open options file", L"Δεν μπορείτε να ανοίξετε το αρχείο επιλογών");
+ addPair("Cannot open directory", L"Δεν μπορείτε να ανοίξετε τον κατάλογο");
+ addPair("Cannot open HTML file %s\n", L"Δεν μπορείτε να ανοίξετε το αρχείο HTML %s\n");
+ addPair("Command execute failure", L"Εντολή να εκτελέσει την αποτυχία");
+ addPair("Command is not installed", L"Η εντολή δεν έχει εγκατασταθεί");
+ addPair("Missing filename in %s\n", L"Λείπει το όνομα αρχείου σε %s\n");
+ addPair("Recursive option with no wildcard", L"Αναδρομικές επιλογή χωρίς μπαλαντέρ");
+ addPair("Did you intend quote the filename", L"Μήπως σκοπεύετε να αναφέρετε το όνομα του αρχείου");
+ addPair("No file to process %s\n", L"Δεν υπάρχει αρχείο για την επεξεργασία %s\n");
+ addPair("Did you intend to use --recursive", L"Μήπως σκοπεύετε να χρησιμοποιήσετε --recursive");
+ addPair("Cannot process UTF-32 encoding", L"δεν μπορεί να επεξεργαστεί UTF-32 κωδικοποίηση");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style έχει λήξει");
+}
+
+Hindi::Hindi() // हिन्दी
+// build the translation vector in the Translation base class
+{
+ // NOTE: Scintilla based editors (CodeBlocks) cannot always edit Hindi.
+ // Use Visual Studio instead.
+ addPair("Formatted %s\n", L"स्वरूपित किया %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"अपरिवर्तित %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"निर्देशिका %s\n");
+ addPair("Exclude %s\n", L"निकालना %s\n");
+ addPair("Exclude (unmatched) %s\n", L"अपवर्जित (बेजोड़) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s स्वरूपित किया %s अपरिवर्तित ");
+ addPair(" seconds ", L" सेकंड ");
+ addPair("%d min %d sec ", L"%d मिनट %d सेकंड ");
+ addPair("%s lines\n", L"%s लाइनों\n");
+ addPair("Using default options file %s\n", L"डिफ़ॉल्ट विकल्प का उपयोग कर फ़ाइल %s\n");
+ addPair("Opening HTML documentation %s\n", L"एचटीएमएल प्रलेखन खोलना %s\n");
+ addPair("Invalid option file options:", L"अवैध विकल्प फ़ाइल विकल्प हैं:");
+ addPair("Invalid command line options:", L"कमांड लाइन विकल्प अवैध:");
+ addPair("For help on options type 'astyle -h'", L"विकल्पों पर मदद के लिए प्रकार 'astyle -h'");
+ addPair("Cannot open options file", L"विकल्प फ़ाइल नहीं खोल सकता है");
+ addPair("Cannot open directory", L"निर्देशिका नहीं खोल सकता");
+ addPair("Cannot open HTML file %s\n", L"HTML फ़ाइल नहीं खोल सकता %s\n");
+ addPair("Command execute failure", L"आदेश विफलता निष्पादित");
+ addPair("Command is not installed", L"कमान स्थापित नहीं है");
+ addPair("Missing filename in %s\n", L"लापता में फ़ाइलनाम %s\n");
+ addPair("Recursive option with no wildcard", L"कोई वाइल्डकार्ड साथ पुनरावर्ती विकल्प");
+ addPair("Did you intend quote the filename", L"क्या आप बोली फ़ाइलनाम का इरादा");
+ addPair("No file to process %s\n", L"कोई फ़ाइल %s प्रक्रिया के लिए\n");
+ addPair("Did you intend to use --recursive", L"क्या आप उपयोग करना चाहते हैं --recursive");
+ addPair("Cannot process UTF-32 encoding", L"UTF-32 कूटबन्धन प्रक्रिया नहीं कर सकते");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style समाप्त किया है");
+}
+
+Hungarian::Hungarian() // Magyar
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formázott %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Változatlan %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Címjegyzék %s\n");
+ addPair("Exclude %s\n", L"Kizár %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Escludere (senza pari) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formázott %s változatlan ");
+ addPair(" seconds ", L" másodperc ");
+ addPair("%d min %d sec ", L"%d jeg %d más ");
+ addPair("%s lines\n", L"%s vonalak\n");
+ addPair("Using default options file %s\n", L"Az alapértelmezett beállítások fájl %s\n");
+ addPair("Opening HTML documentation %s\n", L"Nyitó HTML dokumentáció %s\n");
+ addPair("Invalid option file options:", L"Érvénytelen opció fájlbeállítást:");
+ addPair("Invalid command line options:", L"Érvénytelen parancssori opciók:");
+ addPair("For help on options type 'astyle -h'", L"Ha segítségre van lehetőség típus 'astyle-h'");
+ addPair("Cannot open options file", L"Nem lehet megnyitni beállítási fájlban");
+ addPair("Cannot open directory", L"Nem lehet megnyitni könyvtár");
+ addPair("Cannot open HTML file %s\n", L"Nem lehet megnyitni a HTML fájlt %s\n");
+ addPair("Command execute failure", L"Command végre hiba");
+ addPair("Command is not installed", L"Parancs nincs telepítve");
+ addPair("Missing filename in %s\n", L"Hiányzó fájlnév %s\n");
+ addPair("Recursive option with no wildcard", L"Rekurzív kapcsolót nem wildcard");
+ addPair("Did you intend quote the filename", L"Esetleg kívánja idézni a fájlnév");
+ addPair("No file to process %s\n", L"Nincs fájl feldolgozása %s\n");
+ addPair("Did you intend to use --recursive", L"Esetleg a használni kívánt --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Nem tudja feldolgozni UTF-32 kódolással");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style megszűnt");
+}
+
+Italian::Italian() // Italiano
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formattata %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Immutato %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Elenco %s\n");
+ addPair("Exclude %s\n", L"Escludere %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Escludere (senza pari) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s ormattata %s immutato ");
+ addPair(" seconds ", L" secondo ");
+ addPair("%d min %d sec ", L"%d min %d seg ");
+ addPair("%s lines\n", L"%s linee\n");
+ addPair("Using default options file %s\n", L"Utilizzando file delle opzioni di default %s\n");
+ addPair("Opening HTML documentation %s\n", L"Apertura di documenti HTML %s\n");
+ addPair("Invalid option file options:", L"Opzione non valida file delle opzioni:");
+ addPair("Invalid command line options:", L"Opzioni della riga di comando non valido:");
+ addPair("For help on options type 'astyle -h'", L"Per informazioni sulle opzioni di tipo 'astyle-h'");
+ addPair("Cannot open options file", L"Impossibile aprire il file opzioni");
+ addPair("Cannot open directory", L"Impossibile aprire la directory");
+ addPair("Cannot open HTML file %s\n", L"Impossibile aprire il file HTML %s\n");
+ addPair("Command execute failure", L"Esegui fallimento comando");
+ addPair("Command is not installed", L"Il comando non è installato");
+ addPair("Missing filename in %s\n", L"Nome del file mancante in %s\n");
+ addPair("Recursive option with no wildcard", L"Opzione ricorsiva senza jolly");
+ addPair("Did you intend quote the filename", L"Avete intenzione citare il nome del file");
+ addPair("No file to process %s\n", L"Nessun file al processo %s\n");
+ addPair("Did you intend to use --recursive", L"Hai intenzione di utilizzare --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Non è possibile processo di codifica UTF-32");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style ha terminato");
+}
+
+Japanese::Japanese() // 日本語
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"フォーマット済みの %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"変わりません %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"ディレクトリ %s\n");
+ addPair("Exclude %s\n", L"除外する %s\n");
+ addPair("Exclude (unmatched) %s\n", L"除外する(一致しません) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s フフォーマット済みの %s 変わりません ");
+ addPair(" seconds ", L" 秒 ");
+ addPair("%d min %d sec ", L"%d 分 %d 秒 ");
+ addPair("%s lines\n", L"%s ライン\n");
+ addPair("Using default options file %s\n", L"デフォルトのオプションファイルを使用して、 %s\n");
+ addPair("Opening HTML documentation %s\n", L"オープニングHTMLドキュメント %s\n");
+ addPair("Invalid option file options:", L"無効なオプションファイルのオプション:");
+ addPair("Invalid command line options:", L"無効なコマンドラインオプション:");
+ addPair("For help on options type 'astyle -h'", L"コオプションの種類のヘルプについて'astyle- h'を入力してください");
+ addPair("Cannot open options file", L"オプションファイルを開くことができません");
+ addPair("Cannot open directory", L"ディレクトリを開くことができません。");
+ addPair("Cannot open HTML file %s\n", L"HTMLファイルを開くことができません %s\n");
+ addPair("Command execute failure", L"コマンドが失敗を実行します");
+ addPair("Command is not installed", L"コマンドがインストールされていません");
+ addPair("Missing filename in %s\n", L"%s で、ファイル名がありません\n");
+ addPair("Recursive option with no wildcard", L"無ワイルドカードを使用して再帰的なオプション");
+ addPair("Did you intend quote the filename", L"あなたはファイル名を引用するつもりでした");
+ addPair("No file to process %s\n", L"いいえファイルは処理しないように %s\n");
+ addPair("Did you intend to use --recursive", L"あなたは--recursive使用するつもりでした");
+ addPair("Cannot process UTF-32 encoding", L"UTF - 32エンコーディングを処理できません");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style 終了しました");
+}
+
+Korean::Korean() // 한국의
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"수정됨 %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"변경없음 %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"디렉토리 %s\n");
+ addPair("Exclude %s\n", L"제외됨 %s\n");
+ addPair("Exclude (unmatched) %s\n", L"제외 (NO 일치) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s 수정됨 %s 변경없음 ");
+ addPair(" seconds ", L" 초 ");
+ addPair("%d min %d sec ", L"%d 분 %d 초 ");
+ addPair("%s lines\n", L"%s 라인\n");
+ addPair("Using default options file %s\n", L"기본 구성 파일을 사용 %s\n");
+ addPair("Opening HTML documentation %s\n", L"HTML 문서를 열기 %s\n");
+ addPair("Invalid option file options:", L"잘못된 구성 파일 옵션 :");
+ addPair("Invalid command line options:", L"잘못된 명령줄 옵션 :");
+ addPair("For help on options type 'astyle -h'", L"도움말을 보려면 옵션 유형 'astyle - H'를 사용합니다");
+ addPair("Cannot open options file", L"구성 파일을 열 수 없습니다");
+ addPair("Cannot open directory", L"디렉토리를 열지 못했습니다");
+ addPair("Cannot open HTML file %s\n", L"HTML 파일을 열 수 없습니다 %s\n");
+ addPair("Command execute failure", L"명령 실패를 실행");
+ addPair("Command is not installed", L"명령이 설치되어 있지 않습니다");
+ addPair("Missing filename in %s\n", L"%s 에서 누락된 파일 이름\n");
+ addPair("Recursive option with no wildcard", L"와일드 카드없이 재귀 옵션");
+ addPair("Did you intend quote the filename", L"당신은 파일 이름을 인용하고자하나요");
+ addPair("No file to process %s\n", L"처리할 파일이 없습니다 %s\n");
+ addPair("Did you intend to use --recursive", L"--recursive 를 사용하고자 하십니까");
+ addPair("Cannot process UTF-32 encoding", L"UTF-32 인코딩을 처리할 수 없습니다");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style를 종료합니다");
+}
+
+Norwegian::Norwegian() // Norsk
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formatert %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Uendret %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Katalog %s\n");
+ addPair("Exclude %s\n", L"Ekskluder %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Ekskluder (uovertruffen) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formatert %s uendret ");
+ addPair(" seconds ", L" sekunder ");
+ addPair("%d min %d sec ", L"%d min %d sek? ");
+ addPair("%s lines\n", L"%s linjer\n");
+ addPair("Using default options file %s\n", L"Ved hjelp av standardalternativer fil %s\n");
+ addPair("Opening HTML documentation %s\n", L"Åpning HTML dokumentasjon %s\n");
+ addPair("Invalid option file options:", L"Ugyldige alternativ filalternativer:");
+ addPair("Invalid command line options:", L"Kommandolinjevalg Ugyldige:");
+ addPair("For help on options type 'astyle -h'", L"For hjelp til alternativer type 'astyle -h'");
+ addPair("Cannot open options file", L"Kan ikke åpne alternativer fil");
+ addPair("Cannot open directory", L"Kan ikke åpne katalog");
+ addPair("Cannot open HTML file %s\n", L"Kan ikke åpne HTML-fil %s\n");
+ addPair("Command execute failure", L"Command utføre svikt");
+ addPair("Command is not installed", L"Command er ikke installert");
+ addPair("Missing filename in %s\n", L"Mangler filnavn i %s\n");
+ addPair("Recursive option with no wildcard", L"Rekursiv alternativ uten wildcard");
+ addPair("Did you intend quote the filename", L"Har du tenkt sitere filnavnet");
+ addPair("No file to process %s\n", L"Ingen fil å behandle %s\n");
+ addPair("Did you intend to use --recursive", L"Har du tenkt å bruke --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Kan ikke behandle UTF-32 koding");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style har avsluttet");
+}
+
+Polish::Polish() // Polski
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Sformatowany %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Niezmienione %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Katalog %s\n");
+ addPair("Exclude %s\n", L"Wykluczać %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Wyklucz (niezrównany) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s sformatowany %s niezmienione ");
+ addPair(" seconds ", L" sekund ");
+ addPair("%d min %d sec ", L"%d min %d sek ");
+ addPair("%s lines\n", L"%s linii\n");
+ addPair("Using default options file %s\n", L"Korzystanie z domyślnej opcji %s plik\n");
+ addPair("Opening HTML documentation %s\n", L"Otwarcie dokumentacji HTML %s\n");
+ addPair("Invalid option file options:", L"Nieprawidłowy opcji pliku opcji:");
+ addPair("Invalid command line options:", L"Nieprawidłowe opcje wiersza polecenia:");
+ addPair("For help on options type 'astyle -h'", L"Aby uzyskać pomoc od rodzaju opcji 'astyle -h'");
+ addPair("Cannot open options file", L"Nie można otworzyć pliku opcji");
+ addPair("Cannot open directory", L"Nie można otworzyć katalogu");
+ addPair("Cannot open HTML file %s\n", L"Nie można otworzyć pliku HTML %s\n");
+ addPair("Command execute failure", L"Wykonaj polecenia niepowodzenia");
+ addPair("Command is not installed", L"Polecenie nie jest zainstalowany");
+ addPair("Missing filename in %s\n", L"Brakuje pliku w %s\n");
+ addPair("Recursive option with no wildcard", L"Rekurencyjne opcja bez symboli");
+ addPair("Did you intend quote the filename", L"Czy zamierza Pan podać nazwę pliku");
+ addPair("No file to process %s\n", L"Brak pliku do procesu %s\n");
+ addPair("Did you intend to use --recursive", L"Czy masz zamiar używać --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Nie można procesu kodowania UTF-32");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style został zakończony");
+}
+
+Portuguese::Portuguese() // Português
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formatado %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Inalterado %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Diretório %s\n");
+ addPair("Exclude %s\n", L"Excluir %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Excluir (incomparável) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formatado %s inalterado ");
+ addPair(" seconds ", L" segundo ");
+ addPair("%d min %d sec ", L"%d min %d seg ");
+ addPair("%s lines\n", L"%s linhas\n");
+ addPair("Using default options file %s\n", L"Usando o arquivo de opções padrão %s\n");
+ addPair("Opening HTML documentation %s\n", L"Abrindo a documentação HTML %s\n");
+ addPair("Invalid option file options:", L"Opções de arquivo inválido opção:");
+ addPair("Invalid command line options:", L"Opções de linha de comando inválida:");
+ addPair("For help on options type 'astyle -h'", L"Para obter ajuda sobre as opções de tipo 'astyle -h'");
+ addPair("Cannot open options file", L"Não é possível abrir arquivo de opções");
+ addPair("Cannot open directory", L"Não é possível abrir diretório");
+ addPair("Cannot open HTML file %s\n", L"Não é possível abrir arquivo HTML %s\n");
+ addPair("Command execute failure", L"Executar falha de comando");
+ addPair("Command is not installed", L"Comando não está instalado");
+ addPair("Missing filename in %s\n", L"Filename faltando em %s\n");
+ addPair("Recursive option with no wildcard", L"Opção recursiva sem curinga");
+ addPair("Did you intend quote the filename", L"Será que você pretende citar o nome do arquivo");
+ addPair("No file to process %s\n", L"Nenhum arquivo para processar %s\n");
+ addPair("Did you intend to use --recursive", L"Será que você pretende usar --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Não pode processar a codificação UTF-32");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style terminou");
+}
+
+Romanian::Romanian() // Română
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formatat %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Neschimbat %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Director %s\n");
+ addPair("Exclude %s\n", L"Excludeți %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Excludeți (necompensată) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formatat %s neschimbat ");
+ addPair(" seconds ", L" secunde ");
+ addPair("%d min %d sec ", L"%d min %d sec ");
+ addPair("%s lines\n", L"%s linii\n");
+ addPair("Using default options file %s\n", L"Fișier folosind opțiunile implicite %s\n");
+ addPair("Opening HTML documentation %s\n", L"Documentație HTML deschidere %s\n");
+ addPair("Invalid option file options:", L"Opțiuni de opțiune de fișier nevalide:");
+ addPair("Invalid command line options:", L"Opțiuni de linie de comandă nevalide:");
+ addPair("For help on options type 'astyle -h'", L"Pentru ajutor cu privire la tipul de opțiuni 'astyle -h'");
+ addPair("Cannot open options file", L"Nu se poate deschide fișierul de opțiuni");
+ addPair("Cannot open directory", L"Nu se poate deschide directorul");
+ addPair("Cannot open HTML file %s\n", L"Nu se poate deschide fișierul HTML %s\n");
+ addPair("Command execute failure", L"Comandă executa eșec");
+ addPair("Command is not installed", L"Comanda nu este instalat");
+ addPair("Missing filename in %s\n", L"Lipsă nume de fișier %s\n");
+ addPair("Recursive option with no wildcard", L"Opțiunea recursiv cu nici un wildcard");
+ addPair("Did you intend quote the filename", L"V-intentionati cita numele de fișier");
+ addPair("No file to process %s\n", L"Nu există un fișier pentru a procesa %s\n");
+ addPair("Did you intend to use --recursive", L"V-ați intenționați să utilizați --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Nu se poate procesa codificarea UTF-32");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style a terminat");
+}
+
+Russian::Russian() // русский
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Форматированный %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"без изменений %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"каталог %s\n");
+ addPair("Exclude %s\n", L"исключать %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Исключить (непревзойденный) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s Форматированный %s без изменений ");
+ addPair(" seconds ", L" секунды ");
+ addPair("%d min %d sec ", L"%d мин %d сек ");
+ addPair("%s lines\n", L"%s линий\n");
+ addPair("Using default options file %s\n", L"Использование опции по умолчанию файл %s\n");
+ addPair("Opening HTML documentation %s\n", L"Открытие HTML документации %s\n");
+ addPair("Invalid option file options:", L"Недопустимый файл опций опцию:");
+ addPair("Invalid command line options:", L"Недопустимые параметры командной строки:");
+ addPair("For help on options type 'astyle -h'", L"Для получения справки по 'astyle -h' опций типа");
+ addPair("Cannot open options file", L"Не удается открыть файл параметров");
+ addPair("Cannot open directory", L"Не могу открыть каталог");
+ addPair("Cannot open HTML file %s\n", L"Не удается открыть файл HTML %s\n");
+ addPair("Command execute failure", L"Выполнить команду недостаточности");
+ addPair("Command is not installed", L"Не установлен Команда");
+ addPair("Missing filename in %s\n", L"Отсутствует имя файла в %s\n");
+ addPair("Recursive option with no wildcard", L"Рекурсивный вариант без каких-либо шаблона");
+ addPair("Did you intend quote the filename", L"Вы намерены цитатой файла");
+ addPair("No file to process %s\n", L"Нет файлов для обработки %s\n");
+ addPair("Did you intend to use --recursive", L"Неужели вы собираетесь использовать --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Не удается обработать UTF-32 кодировке");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style прекратил");
+}
+
+Spanish::Spanish() // Español
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formato %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Inalterado %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Directorio %s\n");
+ addPair("Exclude %s\n", L"Excluir %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Excluir (incomparable) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formato %s inalterado ");
+ addPair(" seconds ", L" segundo ");
+ addPair("%d min %d sec ", L"%d min %d seg ");
+ addPair("%s lines\n", L"%s líneas\n");
+ addPair("Using default options file %s\n", L"Uso de las opciones por defecto del archivo %s\n");
+ addPair("Opening HTML documentation %s\n", L"Apertura de documentación HTML %s\n");
+ addPair("Invalid option file options:", L"Opción no válida opciones de archivo:");
+ addPair("Invalid command line options:", L"No válido opciones de línea de comando:");
+ addPair("For help on options type 'astyle -h'", L"Para obtener ayuda sobre las opciones tipo 'astyle -h'");
+ addPair("Cannot open options file", L"No se puede abrir el archivo de opciones");
+ addPair("Cannot open directory", L"No se puede abrir el directorio");
+ addPair("Cannot open HTML file %s\n", L"No se puede abrir el archivo HTML %s\n");
+ addPair("Command execute failure", L"Ejecutar el fracaso de comandos");
+ addPair("Command is not installed", L"El comando no está instalado");
+ addPair("Missing filename in %s\n", L"Falta nombre del archivo en %s\n");
+ addPair("Recursive option with no wildcard", L"Recursiva opción sin comodín");
+ addPair("Did you intend quote the filename", L"Se tiene la intención de citar el nombre de archivo");
+ addPair("No file to process %s\n", L"No existe el fichero a procesar %s\n");
+ addPair("Did you intend to use --recursive", L"Se va a utilizar --recursive");
+ addPair("Cannot process UTF-32 encoding", L"No se puede procesar la codificación UTF-32");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style ha terminado");
+}
+
+Swedish::Swedish() // Svenska
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"Formaterade %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"Oförändrade %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Katalog %s\n");
+ addPair("Exclude %s\n", L"Uteslut %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Uteslut (oöverträffad) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s formaterade %s oförändrade ");
+ addPair(" seconds ", L" sekunder ");
+ addPair("%d min %d sec ", L"%d min %d sek ");
+ addPair("%s lines\n", L"%s linjer\n");
+ addPair("Using default options file %s\n", L"Använda standardalternativ fil %s\n");
+ addPair("Opening HTML documentation %s\n", L"Öppna HTML-dokumentation %s\n");
+ addPair("Invalid option file options:", L"Ogiltigt alternativ fil alternativ:");
+ addPair("Invalid command line options:", L"Ogiltig kommandoraden alternativ:");
+ addPair("For help on options type 'astyle -h'", L"För hjälp om alternativ typ 'astyle -h'");
+ addPair("Cannot open options file", L"Kan inte öppna inställningsfilen");
+ addPair("Cannot open directory", L"Kan inte öppna katalog");
+ addPair("Cannot open HTML file %s\n", L"Kan inte öppna HTML-filen %s\n");
+ addPair("Command execute failure", L"Utför kommando misslyckande");
+ addPair("Command is not installed", L"Kommandot är inte installerat");
+ addPair("Missing filename in %s\n", L"Saknade filnamn i %s\n");
+ addPair("Recursive option with no wildcard", L"Rekursiva alternativ utan jokertecken");
+ addPair("Did you intend quote the filename", L"Visste du tänker citera filnamnet");
+ addPair("No file to process %s\n", L"Ingen fil att bearbeta %s\n");
+ addPair("Did you intend to use --recursive", L"Har du för avsikt att använda --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Kan inte hantera UTF-32 kodning");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style har upphört");
+}
+
+Ukrainian::Ukrainian() // Український
+// build the translation vector in the Translation base class
+{
+ addPair("Formatted %s\n", L"форматований %s\n"); // should align with unchanged
+ addPair("Unchanged %s\n", L"без змін %s\n"); // should align with formatted
+ addPair("Directory %s\n", L"Каталог %s\n");
+ addPair("Exclude %s\n", L"Виключити %s\n");
+ addPair("Exclude (unmatched) %s\n", L"Виключити (неперевершений) %s\n");
+ addPair(" %s formatted %s unchanged ", L" %s відформатований %s без змін ");
+ addPair(" seconds ", L" секунди ");
+ addPair("%d min %d sec ", L"%d хви %d cek ");
+ addPair("%s lines\n", L"%s ліній\n");
+ addPair("Using default options file %s\n", L"Використання файлів опцій за замовчуванням %s\n");
+ addPair("Opening HTML documentation %s\n", L"Відкриття HTML документації %s\n");
+ addPair("Invalid option file options:", L"Неприпустимий файл опцій опцію:");
+ addPair("Invalid command line options:", L"Неприпустима параметри командного рядка:");
+ addPair("For help on options type 'astyle -h'", L"Для отримання довідки по 'astyle -h' опцій типу");
+ addPair("Cannot open options file", L"Не вдається відкрити файл параметрів");
+ addPair("Cannot open directory", L"Не можу відкрити каталог");
+ addPair("Cannot open HTML file %s\n", L"Не вдається відкрити файл HTML %s\n");
+ addPair("Command execute failure", L"Виконати команду недостатності");
+ addPair("Command is not installed", L"Не встановлений Команда");
+ addPair("Missing filename in %s\n", L"Відсутня назва файлу в %s\n");
+ addPair("Recursive option with no wildcard", L"Рекурсивний варіант без будь-яких шаблону");
+ addPair("Did you intend quote the filename", L"Ви маєте намір цитатою файлу");
+ addPair("No file to process %s\n", L"Немає файлів для обробки %s\n");
+ addPair("Did you intend to use --recursive", L"Невже ви збираєтеся використовувати --recursive");
+ addPair("Cannot process UTF-32 encoding", L"Не вдається обробити UTF-32 кодуванні");
+ addPair("\nArtistic Style has terminated", L"\nArtistic Style припинив");
+}
+
+
+#endif // ASTYLE_LIB
+
+} // end of namespace astyle
+
--- /dev/null
+// ASLocalizer.h
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+
+
+#ifndef ASLOCALIZER_H
+#define ASLOCALIZER_H
+
+#include <string>
+#include <vector>
+
+namespace astyle {
+
+using namespace std;
+
+#ifndef ASTYLE_LIB
+
+//-----------------------------------------------------------------------------
+// ASLocalizer class for console build.
+// This class encapsulates all language-dependent settings and is a
+// generalization of the C locale concept.
+//-----------------------------------------------------------------------------
+class Translation;
+
+class ASLocalizer
+{
+public: // functions
+ ASLocalizer();
+ virtual ~ASLocalizer();
+ string getLanguageID() const;
+ const Translation* getTranslationClass() const;
+#ifdef _WIN32
+ void setLanguageFromLCID(size_t lcid);
+#endif
+ void setLanguageFromName(const char* langID);
+ const char* settext(const char* textIn) const;
+
+private: // functions
+ void setTranslationClass();
+
+private: // variables
+ Translation* m_translation; // pointer to a polymorphic Translation class
+ string m_langID; // language identifier from the locale
+ string m_subLangID; // sub language identifier, if needed
+ string m_localeName; // name of the current locale (Linux only)
+ size_t m_lcid; // LCID of the user locale (Windows only)
+};
+
+//----------------------------------------------------------------------------
+// Translation base class.
+//----------------------------------------------------------------------------
+
+class Translation
+// This base class is inherited by the language translation classes.
+// Polymorphism is used to call the correct language translator.
+// This class contains the translation vector and settext translation method.
+// The language vector is built by the language sub classes.
+// NOTE: This class must have virtual methods for typeid() to work.
+// typeid() is used by AStyleTestI18n_Localizer.cpp.
+{
+public:
+ Translation() {}
+ virtual ~Translation() {}
+ string convertToMultiByte(const wstring& wideStr) const;
+ size_t getTranslationVectorSize() const;
+ bool getWideTranslation(const string& stringIn, wstring& wideOut) const;
+ string& translate(const string& stringIn) const;
+
+protected:
+ void addPair(const string& english, const wstring& translated);
+ // variables
+ vector<pair<string, wstring> > m_translation; // translation vector
+
+private:
+ mutable string m_mbTranslation;
+};
+
+//----------------------------------------------------------------------------
+// Translation classes
+// One class for each language.
+// These classes have only a constructor which builds the language vector.
+//----------------------------------------------------------------------------
+
+class Bulgarian : public Translation
+{ public: Bulgarian(); };
+
+class ChineseSimplified : public Translation
+{ public: ChineseSimplified(); };
+
+class ChineseTraditional : public Translation
+{ public: ChineseTraditional(); };
+
+class Dutch : public Translation
+{ public: Dutch(); };
+
+class English : public Translation
+{ public: English(); };
+
+class Estonian : public Translation
+{ public: Estonian(); };
+
+class Finnish : public Translation
+{ public: Finnish(); };
+
+class French : public Translation
+{ public: French(); };
+
+class German : public Translation
+{ public: German(); };
+
+class Greek : public Translation
+{ public: Greek(); };
+
+class Hindi : public Translation
+{ public: Hindi(); };
+
+class Hungarian : public Translation
+{ public: Hungarian(); };
+
+class Italian : public Translation
+{ public: Italian(); };
+
+class Japanese : public Translation
+{ public: Japanese(); };
+
+class Korean : public Translation
+{ public: Korean(); };
+
+class Norwegian : public Translation
+{ public: Norwegian(); };
+
+class Polish : public Translation
+{ public: Polish(); };
+
+class Portuguese : public Translation
+{ public: Portuguese(); };
+
+class Romanian : public Translation
+{ public: Romanian(); };
+
+class Russian : public Translation
+{ public: Russian(); };
+
+class Spanish : public Translation
+{ public: Spanish(); };
+
+class Swedish : public Translation
+{ public: Swedish(); };
+
+class Ukrainian : public Translation
+{ public: Ukrainian(); };
+
+
+#endif // ASTYLE_LIB
+
+} // namespace astyle
+
+#endif // ASLOCALIZER_H
--- /dev/null
+// ASResource.cpp
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+
+//-----------------------------------------------------------------------------
+// headers
+//-----------------------------------------------------------------------------
+
+#include "astyle.h"
+#include <algorithm>
+
+//-----------------------------------------------------------------------------
+// astyle namespace
+//-----------------------------------------------------------------------------
+
+namespace astyle {
+//
+const string ASResource::_AS_EXCEPT = string("__except");
+const string ASResource::_AS_FINALLY = string("__finally");
+const string ASResource::_AS_TRY = string("__try");
+const string ASResource::AS_ADD = string("add");
+const string ASResource::AS_AUTO = string("auto");
+const string ASResource::AS_AUTORELEASEPOOL = string("autoreleasepool");
+const string ASResource::AS_CASE = string("case");
+const string ASResource::AS_CATCH = string("catch");
+const string ASResource::AS_CLASS = string("class");
+const string ASResource::AS_CONST = string("const");
+const string ASResource::AS_CONST_CAST = string("const_cast");
+const string ASResource::AS_DEFAULT = string("default");
+const string ASResource::AS_DELEGATE = string("delegate");
+const string ASResource::AS_DELETE = string("delete");
+const string ASResource::AS_DO = string("do");
+const string ASResource::AS_DYNAMIC_CAST = string("dynamic_cast");
+const string ASResource::AS_ELSE = string("else");
+const string ASResource::AS_END = string("end");
+const string ASResource::AS_ENUM = string("enum");
+const string ASResource::AS_EXTERN = string("extern");
+const string ASResource::AS_FINALLY = string("finally");
+const string ASResource::AS_FIXED = string("fixed");
+const string ASResource::AS_FOR = string("for");
+const string ASResource::AS_FOREACH = string("foreach");
+const string ASResource::AS_FOREVER = string("forever");
+const string ASResource::AS_GET = string("get");
+const string ASResource::AS_IF = string("if");
+const string ASResource::AS_INTERFACE = string("interface");
+const string ASResource::AS_INTERRUPT = string("interrupt");
+const string ASResource::AS_LET = string("let");
+const string ASResource::AS_LOCK = string("lock");
+const string ASResource::AS_MODULE = string("module"); // CORBA IDL module definition
+const string ASResource::AS_NAMESPACE = string("namespace");
+const string ASResource::AS_NEW = string("new");
+const string ASResource::AS_NOEXCEPT = string("noexcept");
+const string ASResource::AS_NS_DURING = string("NS_DURING");
+const string ASResource::AS_NS_HANDLER = string("NS_HANDLER");
+const string ASResource::AS_OPERATOR = string("operator");
+const string ASResource::AS_OVERRIDE = string("override");
+const string ASResource::AS_PRIVATE = string("private");
+const string ASResource::AS_PROTECTED = string("protected");
+const string ASResource::AS_PUBLIC = string("public");
+const string ASResource::AS_QFOREACH = string("Q_FOREACH");
+const string ASResource::AS_QFOREVER = string("Q_FOREVER");
+const string ASResource::AS_REINTERPRET_CAST = string("reinterpret_cast");
+const string ASResource::AS_REMOVE = string("remove");
+const string ASResource::AS_SEALED = string("sealed");
+const string ASResource::AS_SELECTOR = string("selector");
+const string ASResource::AS_SET = string("set");
+const string ASResource::AS_STATIC = string("static");
+const string ASResource::AS_STATIC_CAST = string("static_cast");
+const string ASResource::AS_STRUCT = string("struct");
+const string ASResource::AS_SWITCH = string("switch");
+const string ASResource::AS_SYNCHRONIZED = string("synchronized");
+const string ASResource::AS_TEMPLATE = string("template");
+const string ASResource::AS_THROW = string("throw");
+const string ASResource::AS_THROWS = string("throws");
+const string ASResource::AS_TRY = string("try");
+const string ASResource::AS_UNCHECKED = string("unchecked");
+const string ASResource::AS_UNION = string("union");
+const string ASResource::AS_UNSAFE = string("unsafe");
+const string ASResource::AS_USING = string("using");
+const string ASResource::AS_VOLATILE = string("volatile");
+const string ASResource::AS_WHERE = string("where");
+const string ASResource::AS_WHILE = string("while");
+
+const string ASResource::AS_ASM = string("asm");
+const string ASResource::AS__ASM__ = string("__asm__");
+const string ASResource::AS_MS_ASM = string("_asm");
+const string ASResource::AS_MS__ASM = string("__asm");
+
+const string ASResource::AS_BAR_DEFINE = string("#define");
+const string ASResource::AS_BAR_INCLUDE = string("#include");
+const string ASResource::AS_BAR_IF = string("#if");
+const string ASResource::AS_BAR_EL = string("#el");
+const string ASResource::AS_BAR_ENDIF = string("#endif");
+
+const string ASResource::AS_OPEN_BRACE = string("{");
+const string ASResource::AS_CLOSE_BRACE = string("}");
+const string ASResource::AS_OPEN_LINE_COMMENT = string("//");
+const string ASResource::AS_OPEN_COMMENT = string("/*");
+const string ASResource::AS_CLOSE_COMMENT = string("*/");
+
+const string ASResource::AS_ASSIGN = string("=");
+const string ASResource::AS_PLUS_ASSIGN = string("+=");
+const string ASResource::AS_MINUS_ASSIGN = string("-=");
+const string ASResource::AS_MULT_ASSIGN = string("*=");
+const string ASResource::AS_DIV_ASSIGN = string("/=");
+const string ASResource::AS_MOD_ASSIGN = string("%=");
+const string ASResource::AS_OR_ASSIGN = string("|=");
+const string ASResource::AS_AND_ASSIGN = string("&=");
+const string ASResource::AS_XOR_ASSIGN = string("^=");
+const string ASResource::AS_GR_GR_ASSIGN = string(">>=");
+const string ASResource::AS_LS_LS_ASSIGN = string("<<=");
+const string ASResource::AS_GR_GR_GR_ASSIGN = string(">>>=");
+const string ASResource::AS_LS_LS_LS_ASSIGN = string("<<<=");
+const string ASResource::AS_GCC_MIN_ASSIGN = string("<?");
+const string ASResource::AS_GCC_MAX_ASSIGN = string(">?");
+
+const string ASResource::AS_RETURN = string("return");
+const string ASResource::AS_CIN = string("cin");
+const string ASResource::AS_COUT = string("cout");
+const string ASResource::AS_CERR = string("cerr");
+
+const string ASResource::AS_EQUAL = string("==");
+const string ASResource::AS_PLUS_PLUS = string("++");
+const string ASResource::AS_MINUS_MINUS = string("--");
+const string ASResource::AS_NOT_EQUAL = string("!=");
+const string ASResource::AS_GR_EQUAL = string(">=");
+const string ASResource::AS_GR_GR = string(">>");
+const string ASResource::AS_GR_GR_GR = string(">>>");
+const string ASResource::AS_LS_EQUAL = string("<=");
+const string ASResource::AS_LS_LS = string("<<");
+const string ASResource::AS_LS_LS_LS = string("<<<");
+const string ASResource::AS_QUESTION_QUESTION = string("??");
+const string ASResource::AS_LAMBDA = string("=>"); // C# lambda expression arrow
+const string ASResource::AS_ARROW = string("->");
+const string ASResource::AS_AND = string("&&");
+const string ASResource::AS_OR = string("||");
+const string ASResource::AS_SCOPE_RESOLUTION = string("::");
+
+const string ASResource::AS_PLUS = string("+");
+const string ASResource::AS_MINUS = string("-");
+const string ASResource::AS_MULT = string("*");
+const string ASResource::AS_DIV = string("/");
+const string ASResource::AS_MOD = string("%");
+const string ASResource::AS_GR = string(">");
+const string ASResource::AS_LS = string("<");
+const string ASResource::AS_NOT = string("!");
+const string ASResource::AS_BIT_OR = string("|");
+const string ASResource::AS_BIT_AND = string("&");
+const string ASResource::AS_BIT_NOT = string("~");
+const string ASResource::AS_BIT_XOR = string("^");
+const string ASResource::AS_QUESTION = string("?");
+const string ASResource::AS_COLON = string(":");
+const string ASResource::AS_COMMA = string(",");
+const string ASResource::AS_SEMICOLON = string(";");
+
+/**
+ * Sort comparison function.
+ * Compares the length of the value of pointers in the vectors.
+ * The LONGEST strings will be first in the vector.
+ *
+ * @param a and b, the string pointers to be compared.
+ */
+bool sortOnLength(const string* a, const string* b)
+{
+ return (*a).length() > (*b).length();
+}
+
+/**
+ * Sort comparison function.
+ * Compares the value of pointers in the vectors.
+ *
+ * @param a and b, the string pointers to be compared.
+ */
+bool sortOnName(const string* a, const string* b)
+{
+ return *a < *b;
+}
+
+/**
+ * Build the vector of assignment operators.
+ * Used by BOTH ASFormatter.cpp and ASBeautifier.cpp
+ *
+ * @param assignmentOperators a reference to the vector to be built.
+ */
+void ASResource::buildAssignmentOperators(vector<const string*>* assignmentOperators)
+{
+ const size_t elements = 15;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ assignmentOperators->reserve(elements);
+ reserved = true;
+ }
+
+ assignmentOperators->emplace_back(&AS_ASSIGN);
+ assignmentOperators->emplace_back(&AS_PLUS_ASSIGN);
+ assignmentOperators->emplace_back(&AS_MINUS_ASSIGN);
+ assignmentOperators->emplace_back(&AS_MULT_ASSIGN);
+ assignmentOperators->emplace_back(&AS_DIV_ASSIGN);
+ assignmentOperators->emplace_back(&AS_MOD_ASSIGN);
+ assignmentOperators->emplace_back(&AS_OR_ASSIGN);
+ assignmentOperators->emplace_back(&AS_AND_ASSIGN);
+ assignmentOperators->emplace_back(&AS_XOR_ASSIGN);
+
+ // Java
+ assignmentOperators->emplace_back(&AS_GR_GR_GR_ASSIGN);
+ assignmentOperators->emplace_back(&AS_GR_GR_ASSIGN);
+ assignmentOperators->emplace_back(&AS_LS_LS_ASSIGN);
+
+ // Unknown
+ assignmentOperators->emplace_back(&AS_LS_LS_LS_ASSIGN);
+
+ assert(assignmentOperators->size() < elements);
+ sort(assignmentOperators->begin(), assignmentOperators->end(), sortOnLength);
+}
+
+/**
+ * Build the vector of C++ cast operators.
+ * Used by ONLY ASFormatter.cpp
+ *
+ * @param castOperators a reference to the vector to be built.
+ */
+void ASResource::buildCastOperators(vector<const string*>* castOperators)
+{
+ const size_t elements = 5;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ castOperators->reserve(elements);
+ reserved = true;
+ }
+
+ castOperators->emplace_back(&AS_CONST_CAST);
+ castOperators->emplace_back(&AS_DYNAMIC_CAST);
+ castOperators->emplace_back(&AS_REINTERPRET_CAST);
+ castOperators->emplace_back(&AS_STATIC_CAST);
+
+ assert(castOperators->size() < elements);
+ sort(castOperators->begin(), castOperators->end(), sortOnName);
+}
+
+/**
+ * Build the vector of header words.
+ * Used by BOTH ASFormatter.cpp and ASBeautifier.cpp
+ *
+ * @param headers a reference to the vector to be built.
+ */
+void ASResource::buildHeaders(vector<const string*>* headers, int fileType, bool beautifier)
+{
+ const size_t elements = 25;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ headers->reserve(elements);
+ reserved = true;
+ }
+
+ headers->emplace_back(&AS_IF);
+ headers->emplace_back(&AS_ELSE);
+ headers->emplace_back(&AS_FOR);
+ headers->emplace_back(&AS_WHILE);
+ headers->emplace_back(&AS_DO);
+ headers->emplace_back(&AS_SWITCH);
+ headers->emplace_back(&AS_CASE);
+ headers->emplace_back(&AS_DEFAULT);
+ headers->emplace_back(&AS_TRY);
+ headers->emplace_back(&AS_CATCH);
+ headers->emplace_back(&AS_QFOREACH); // QT
+ headers->emplace_back(&AS_QFOREVER); // QT
+ headers->emplace_back(&AS_FOREACH); // QT & C#
+ headers->emplace_back(&AS_FOREVER); // Qt & Boost
+
+ if (fileType == C_TYPE)
+ {
+ headers->emplace_back(&_AS_TRY); // __try
+ headers->emplace_back(&_AS_FINALLY); // __finally
+ headers->emplace_back(&_AS_EXCEPT); // __except
+ }
+ if (fileType == JAVA_TYPE)
+ {
+ headers->emplace_back(&AS_FINALLY);
+ headers->emplace_back(&AS_SYNCHRONIZED);
+ }
+
+ if (fileType == SHARP_TYPE)
+ {
+ headers->emplace_back(&AS_FINALLY);
+ headers->emplace_back(&AS_LOCK);
+ headers->emplace_back(&AS_FIXED);
+ headers->emplace_back(&AS_GET);
+ headers->emplace_back(&AS_SET);
+ headers->emplace_back(&AS_ADD);
+ headers->emplace_back(&AS_REMOVE);
+ headers->emplace_back(&AS_USING);
+ }
+
+ if (beautifier)
+ {
+ if (fileType == C_TYPE)
+ {
+ headers->emplace_back(&AS_TEMPLATE);
+ }
+
+ if (fileType == JAVA_TYPE)
+ {
+ headers->emplace_back(&AS_STATIC); // for static constructor
+ }
+ }
+
+ assert(headers->size() < elements);
+ sort(headers->begin(), headers->end(), sortOnName);
+}
+
+/**
+ * Build the vector of indentable headers.
+ * Used by ONLY ASBeautifier.cpp
+ *
+ * @param indentableHeaders a reference to the vector to be built.
+ */
+void ASResource::buildIndentableHeaders(vector<const string*>* indentableHeaders)
+{
+ indentableHeaders->emplace_back(&AS_RETURN);
+
+// sort(indentableHeaders->begin(), indentableHeaders->end(), sortOnName);
+}
+
+/**
+* Build the vector of indentable macros pairs.
+* Initialized by ASFormatter, used by ONLY ASEnhancer.cpp
+*
+* @param indentableMacros a reference to the vector to be built.
+*/
+void ASResource::buildIndentableMacros(vector<const pair<const string, const string>* >* indentableMacros)
+{
+ const size_t elements = 10;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ indentableMacros->reserve(elements);
+ reserved = true;
+ }
+
+ // the pairs must be retained in memory because of pair pointers
+ typedef pair<const string, const string> macro_pair;
+ static const macro_pair macros[] =
+ {
+ // wxWidgets
+ macro_pair("BEGIN_EVENT_TABLE", "END_EVENT_TABLE"),
+ macro_pair("wxBEGIN_EVENT_TABLE", "wxEND_EVENT_TABLE"),
+ // MFC
+ macro_pair("BEGIN_DISPATCH_MAP", "END_DISPATCH_MAP"),
+ macro_pair("BEGIN_EVENT_MAP", "END_EVENT_MAP"),
+ macro_pair("BEGIN_MESSAGE_MAP", "END_MESSAGE_MAP"),
+ macro_pair("BEGIN_PROPPAGEIDS", "END_PROPPAGEIDS"),
+ };
+
+ size_t entries = sizeof(macros) / sizeof(macros[0]);
+ for (size_t i = 0; i < entries; i++)
+ indentableMacros->emplace_back(¯os[i]);
+
+ assert(indentableMacros->size() < elements);
+}
+
+/**
+ * Build the vector of non-assignment operators.
+ * Used by ONLY ASBeautifier.cpp
+ *
+ * @param nonAssignmentOperators a reference to the vector to be built.
+ */
+void ASResource::buildNonAssignmentOperators(vector<const string*>* nonAssignmentOperators)
+{
+ const size_t elements = 15;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ nonAssignmentOperators->reserve(elements);
+ reserved = true;
+ }
+
+ nonAssignmentOperators->emplace_back(&AS_EQUAL);
+ nonAssignmentOperators->emplace_back(&AS_PLUS_PLUS);
+ nonAssignmentOperators->emplace_back(&AS_MINUS_MINUS);
+ nonAssignmentOperators->emplace_back(&AS_NOT_EQUAL);
+ nonAssignmentOperators->emplace_back(&AS_GR_EQUAL);
+ nonAssignmentOperators->emplace_back(&AS_GR_GR_GR);
+ nonAssignmentOperators->emplace_back(&AS_GR_GR);
+ nonAssignmentOperators->emplace_back(&AS_LS_EQUAL);
+ nonAssignmentOperators->emplace_back(&AS_LS_LS_LS);
+ nonAssignmentOperators->emplace_back(&AS_LS_LS);
+ nonAssignmentOperators->emplace_back(&AS_ARROW);
+ nonAssignmentOperators->emplace_back(&AS_AND);
+ nonAssignmentOperators->emplace_back(&AS_OR);
+ nonAssignmentOperators->emplace_back(&AS_LAMBDA);
+
+ assert(nonAssignmentOperators->size() < elements);
+ sort(nonAssignmentOperators->begin(), nonAssignmentOperators->end(), sortOnLength);
+}
+
+/**
+ * Build the vector of header non-paren headers.
+ * Used by BOTH ASFormatter.cpp and ASBeautifier.cpp.
+ * NOTE: Non-paren headers should also be included in the headers vector.
+ *
+ * @param nonParenHeaders a reference to the vector to be built.
+ */
+void ASResource::buildNonParenHeaders(vector<const string*>* nonParenHeaders, int fileType, bool beautifier)
+{
+ const size_t elements = 20;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ nonParenHeaders->reserve(elements);
+ reserved = true;
+ }
+
+ nonParenHeaders->emplace_back(&AS_ELSE);
+ nonParenHeaders->emplace_back(&AS_DO);
+ nonParenHeaders->emplace_back(&AS_TRY);
+ nonParenHeaders->emplace_back(&AS_CATCH); // can be paren or non-paren
+ nonParenHeaders->emplace_back(&AS_CASE); // can be paren or non-paren
+ nonParenHeaders->emplace_back(&AS_DEFAULT);
+ nonParenHeaders->emplace_back(&AS_QFOREVER); // QT
+ nonParenHeaders->emplace_back(&AS_FOREVER); // Boost
+
+ if (fileType == C_TYPE)
+ {
+ nonParenHeaders->emplace_back(&_AS_TRY); // __try
+ nonParenHeaders->emplace_back(&_AS_FINALLY); // __finally
+ }
+ if (fileType == JAVA_TYPE)
+ {
+ nonParenHeaders->emplace_back(&AS_FINALLY);
+ }
+
+ if (fileType == SHARP_TYPE)
+ {
+ nonParenHeaders->emplace_back(&AS_FINALLY);
+ nonParenHeaders->emplace_back(&AS_GET);
+ nonParenHeaders->emplace_back(&AS_SET);
+ nonParenHeaders->emplace_back(&AS_ADD);
+ nonParenHeaders->emplace_back(&AS_REMOVE);
+ }
+
+ if (beautifier)
+ {
+ if (fileType == C_TYPE)
+ {
+ nonParenHeaders->emplace_back(&AS_TEMPLATE);
+ }
+ if (fileType == JAVA_TYPE)
+ {
+ nonParenHeaders->emplace_back(&AS_STATIC);
+ }
+ }
+
+ assert(nonParenHeaders->size() < elements);
+ sort(nonParenHeaders->begin(), nonParenHeaders->end(), sortOnName);
+}
+
+/**
+ * Build the vector of operators.
+ * Used by ONLY ASFormatter.cpp
+ *
+ * @param operators a reference to the vector to be built.
+ */
+void ASResource::buildOperators(vector<const string*>* operators, int fileType)
+{
+ const size_t elements = 50;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ operators->reserve(elements);
+ reserved = true;
+ }
+
+
+ operators->emplace_back(&AS_PLUS_ASSIGN);
+ operators->emplace_back(&AS_MINUS_ASSIGN);
+ operators->emplace_back(&AS_MULT_ASSIGN);
+ operators->emplace_back(&AS_DIV_ASSIGN);
+ operators->emplace_back(&AS_MOD_ASSIGN);
+ operators->emplace_back(&AS_OR_ASSIGN);
+ operators->emplace_back(&AS_AND_ASSIGN);
+ operators->emplace_back(&AS_XOR_ASSIGN);
+ operators->emplace_back(&AS_EQUAL);
+ operators->emplace_back(&AS_PLUS_PLUS);
+ operators->emplace_back(&AS_MINUS_MINUS);
+ operators->emplace_back(&AS_NOT_EQUAL);
+ operators->emplace_back(&AS_GR_EQUAL);
+ operators->emplace_back(&AS_GR_GR_GR_ASSIGN);
+ operators->emplace_back(&AS_GR_GR_ASSIGN);
+ operators->emplace_back(&AS_GR_GR_GR);
+ operators->emplace_back(&AS_GR_GR);
+ operators->emplace_back(&AS_LS_EQUAL);
+ operators->emplace_back(&AS_LS_LS_LS_ASSIGN);
+ operators->emplace_back(&AS_LS_LS_ASSIGN);
+ operators->emplace_back(&AS_LS_LS_LS);
+ operators->emplace_back(&AS_LS_LS);
+ operators->emplace_back(&AS_QUESTION_QUESTION);
+ operators->emplace_back(&AS_LAMBDA);
+ operators->emplace_back(&AS_ARROW);
+ operators->emplace_back(&AS_AND);
+ operators->emplace_back(&AS_OR);
+ operators->emplace_back(&AS_SCOPE_RESOLUTION);
+ operators->emplace_back(&AS_PLUS);
+ operators->emplace_back(&AS_MINUS);
+ operators->emplace_back(&AS_MULT);
+ operators->emplace_back(&AS_DIV);
+ operators->emplace_back(&AS_MOD);
+ operators->emplace_back(&AS_QUESTION);
+ operators->emplace_back(&AS_COLON);
+ operators->emplace_back(&AS_ASSIGN);
+ operators->emplace_back(&AS_LS);
+ operators->emplace_back(&AS_GR);
+ operators->emplace_back(&AS_NOT);
+ operators->emplace_back(&AS_BIT_OR);
+ operators->emplace_back(&AS_BIT_AND);
+ operators->emplace_back(&AS_BIT_NOT);
+ operators->emplace_back(&AS_BIT_XOR);
+ if (fileType == C_TYPE)
+ {
+ operators->emplace_back(&AS_GCC_MIN_ASSIGN);
+ operators->emplace_back(&AS_GCC_MAX_ASSIGN);
+ }
+
+ assert(operators->size() < elements);
+ sort(operators->begin(), operators->end(), sortOnLength);
+}
+
+/**
+ * Build the vector of pre-block statements.
+ * Used by ONLY ASBeautifier.cpp
+ * NOTE: Cannot be both a header and a preBlockStatement.
+ *
+ * @param preBlockStatements a reference to the vector to be built.
+ */
+void ASResource::buildPreBlockStatements(vector<const string*>* preBlockStatements, int fileType)
+{
+ const size_t elements = 10;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ preBlockStatements->reserve(elements);
+ reserved = true;
+ }
+
+ preBlockStatements->emplace_back(&AS_CLASS);
+ if (fileType == C_TYPE)
+ {
+ preBlockStatements->emplace_back(&AS_STRUCT);
+ preBlockStatements->emplace_back(&AS_UNION);
+ preBlockStatements->emplace_back(&AS_NAMESPACE);
+ preBlockStatements->emplace_back(&AS_MODULE); // for CORBA IDL
+ preBlockStatements->emplace_back(&AS_INTERFACE); // for CORBA IDL
+ }
+ if (fileType == JAVA_TYPE)
+ {
+ preBlockStatements->emplace_back(&AS_INTERFACE);
+ preBlockStatements->emplace_back(&AS_THROWS);
+ }
+ if (fileType == SHARP_TYPE)
+ {
+ preBlockStatements->emplace_back(&AS_INTERFACE);
+ preBlockStatements->emplace_back(&AS_NAMESPACE);
+ preBlockStatements->emplace_back(&AS_WHERE);
+ preBlockStatements->emplace_back(&AS_STRUCT);
+ }
+
+ assert(preBlockStatements->size() < elements);
+ sort(preBlockStatements->begin(), preBlockStatements->end(), sortOnName);
+}
+
+/**
+ * Build the vector of pre-command headers.
+ * Used by BOTH ASFormatter.cpp and ASBeautifier.cpp.
+ * NOTE: Cannot be both a header and a preCommandHeader.
+ *
+ * A preCommandHeader is in a function definition between
+ * the closing paren and the opening brace.
+ * e.g. in "void foo() const {}", "const" is a preCommandHeader.
+ */
+void ASResource::buildPreCommandHeaders(vector<const string*>* preCommandHeaders, int fileType)
+{
+ const size_t elements = 10;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ preCommandHeaders->reserve(elements);
+ reserved = true;
+ }
+
+ if (fileType == C_TYPE)
+ {
+ preCommandHeaders->emplace_back(&AS_CONST);
+ preCommandHeaders->emplace_back(&AS_VOLATILE);
+ preCommandHeaders->emplace_back(&AS_INTERRUPT);
+ preCommandHeaders->emplace_back(&AS_NOEXCEPT);
+ preCommandHeaders->emplace_back(&AS_OVERRIDE);
+ preCommandHeaders->emplace_back(&AS_SEALED); // Visual C only
+ preCommandHeaders->emplace_back(&AS_AUTORELEASEPOOL); // Obj-C only
+ }
+
+ if (fileType == JAVA_TYPE)
+ {
+ preCommandHeaders->emplace_back(&AS_THROWS);
+ }
+
+ if (fileType == SHARP_TYPE)
+ {
+ preCommandHeaders->emplace_back(&AS_WHERE);
+ }
+
+ assert(preCommandHeaders->size() < elements);
+ sort(preCommandHeaders->begin(), preCommandHeaders->end(), sortOnName);
+}
+
+/**
+ * Build the vector of pre-definition headers.
+ * Used by ONLY ASFormatter.cpp
+ * NOTE: Do NOT add 'enum' here. It is an array type brace.
+ * NOTE: Do NOT add 'extern' here. Do not want an extra indent.
+ *
+ * @param preDefinitionHeaders a reference to the vector to be built.
+ */
+void ASResource::buildPreDefinitionHeaders(vector<const string*>* preDefinitionHeaders, int fileType)
+{
+ const size_t elements = 10;
+ static bool reserved = false;
+ if (!reserved)
+ {
+ preDefinitionHeaders->reserve(elements);
+ reserved = true;
+ }
+
+ preDefinitionHeaders->emplace_back(&AS_CLASS);
+ if (fileType == C_TYPE)
+ {
+ preDefinitionHeaders->emplace_back(&AS_STRUCT);
+ preDefinitionHeaders->emplace_back(&AS_UNION);
+ preDefinitionHeaders->emplace_back(&AS_NAMESPACE);
+ preDefinitionHeaders->emplace_back(&AS_MODULE); // for CORBA IDL
+ preDefinitionHeaders->emplace_back(&AS_INTERFACE); // for CORBA IDL
+ }
+ if (fileType == JAVA_TYPE)
+ {
+ preDefinitionHeaders->emplace_back(&AS_INTERFACE);
+ }
+ if (fileType == SHARP_TYPE)
+ {
+ preDefinitionHeaders->emplace_back(&AS_STRUCT);
+ preDefinitionHeaders->emplace_back(&AS_INTERFACE);
+ preDefinitionHeaders->emplace_back(&AS_NAMESPACE);
+ }
+
+ assert(preDefinitionHeaders->size() < elements);
+ sort(preDefinitionHeaders->begin(), preDefinitionHeaders->end(), sortOnName);
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * ASBase Functions
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// check if a specific line position contains a header.
+const string* ASBase::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 nullptr;
+}
+
+// check if a specific line position contains a keyword.
+bool ASBase::findKeyword(const string& line, int i, const string& keyword) const
+{
+ assert(isCharPotentialHeader(line, i));
+ // check the word
+ const size_t keywordLength = keyword.length();
+ const size_t wordEnd = i + keywordLength;
+ if (wordEnd > line.length())
+ return false;
+ if (line.compare(i, keywordLength, keyword) != 0)
+ return false;
+ // check that this is not part of a longer word
+ if (wordEnd == line.length())
+ return true;
+ if (isLegalNameChar(line[wordEnd]))
+ return false;
+ // is not a keyword if part of a definition
+ const char peekChar = peekNextChar(line, (int) wordEnd - 1);
+ if (peekChar == ',' || peekChar == ')')
+ return false;
+ return true;
+}
+
+// check if a specific line position contains an operator.
+const string* ASBase::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 nullptr;
+}
+
+// get the current word on a line
+// index must point to the beginning of the word
+string ASBase::getCurrentWord(const string& line, size_t index) const
+{
+ assert(isCharPotentialHeader(line, index));
+ size_t lineLength = line.length();
+ size_t i;
+ for (i = index; i < lineLength; i++)
+ {
+ if (!isLegalNameChar(line[i]))
+ break;
+ }
+ return line.substr(index, i - index);
+}
+
+// check if a specific character can be used in a legal variable/method/class name
+bool ASBase::isLegalNameChar(char ch) const
+{
+ if (isWhiteSpace(ch))
+ return false;
+ if ((unsigned char) ch > 127)
+ return false;
+ return (isalnum((unsigned char) ch)
+ || ch == '.' || ch == '_'
+ || (isJavaStyle() && ch == '$')
+ || (isSharpStyle() && ch == '@')); // may be used as a prefix
+}
+
+// check if a specific character can be part of a header
+bool ASBase::isCharPotentialHeader(const string& line, size_t i) const
+{
+ assert(!isWhiteSpace(line[i]));
+ char prevCh = ' ';
+ if (i > 0)
+ prevCh = line[i - 1];
+ if (!isLegalNameChar(prevCh) && isLegalNameChar(line[i]))
+ return true;
+ return false;
+}
+
+// check if a specific character can be part of an operator
+bool ASBase::isCharPotentialOperator(char ch) const
+{
+ assert(!isWhiteSpace(ch));
+ if ((unsigned) ch > 127)
+ return false;
+ return (ispunct((unsigned char) ch)
+ && ch != '{' && ch != '}'
+ && ch != '(' && ch != ')'
+ && ch != '[' && ch != ']'
+ && ch != ';' && ch != ','
+ && ch != '#' && ch != '\\'
+ && ch != '\'' && ch != '\"');
+}
+
+// check if a specific character is a digit
+// NOTE: Visual C isdigit() gives assert error if char > 256
+bool ASBase::isDigit(char ch) const
+{
+ return (ch >= '0' && ch <= '9');
+}
+
+// check if a specific character is a digit separator
+bool ASBase::isDigitSeparator(const string& line, int i) const
+{
+ assert(line[i] == '\'');
+ // casting to (unsigned char) eliminates negative characters
+ // will get a "Debug Assertion Failed" if not cast
+ bool foundDigitSeparator = i > 0
+ && isxdigit((unsigned char) line[i - 1])
+ && i < (int) line.length() - 1
+ && isxdigit((unsigned char) line[i + 1]);
+ return foundDigitSeparator;
+}
+
+// peek at the next unread character.
+char ASBase::peekNextChar(const string& line, int i) const
+{
+ char ch = ' ';
+ size_t peekNum = line.find_first_not_of(" \t", i + 1);
+ if (peekNum == string::npos)
+ return ch;
+ ch = line[peekNum];
+ return ch;
+}
+
+} // end namespace astyle
--- /dev/null
+SET(ASTYLE_SRCS
+ astyle_main.cpp
+ ASBeautifier.cpp
+ ASEnhancer.cpp
+ ASFormatter.cpp
+ ASLocalizer.cpp
+ ASResource.cpp
+)
+
+if (CMAKE_VERSION VERSION_LESS "3.1")
+ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ set (CMAKE_CXX_FLAGS "--std=c++11 ${CMAKE_CXX_FLAGS}")
+ endif ()
+else ()
+ set (CMAKE_CXX_STANDARD 11)
+endif ()
+
+# No warnings for astyle build
+IF(NOT MSVC)
+ SET_SOURCE_FILES_PROPERTIES(${ASTYLE_SRCS} PROPERTIES COMPILE_FLAGS -w)
+ENDIF(NOT MSVC)
+ADD_EXECUTABLE(opjstyle ${ASTYLE_SRCS})
+SET_TARGET_PROPERTIES(opjstyle PROPERTIES LINKER_LANGUAGE CXX)
+SET_TARGET_PROPERTIES(opjstyle PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/scripts)
+
+IF (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lstdc++")
+ENDIF (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
--- /dev/null
+### MIT License
+
+Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+// astyle.h
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+
+#ifndef ASTYLE_H
+#define ASTYLE_H
+
+//-----------------------------------------------------------------------------
+// headers
+//-----------------------------------------------------------------------------
+
+#ifdef __VMS
+ #define __USE_STD_IOSTREAM 1
+ #include <assert>
+#else
+ #include <cassert>
+#endif
+
+#include <cctype>
+#include <iostream> // for cout
+#include <memory>
+#include <string>
+#include <vector>
+
+#ifdef __GNUC__
+ #include <cstring> // need both string and cstring for GCC
+#endif
+
+//-----------------------------------------------------------------------------
+// declarations
+//-----------------------------------------------------------------------------
+
+#ifdef _MSC_VER
+ #pragma warning(disable: 4267) // conversion from size_t to int
+#endif
+
+#ifdef __BORLANDC__
+ #pragma warn -8004 // variable is assigned a value that is never used
+#endif
+
+#ifdef __INTEL_COMPILER
+ #pragma warning(disable: 383) // value copied to temporary, reference to temporary used
+ #pragma warning(disable: 981) // operands are evaluated in unspecified order
+#endif
+
+#ifdef __clang__
+ #pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
+//-----------------------------------------------------------------------------
+// astyle namespace
+//-----------------------------------------------------------------------------
+
+namespace astyle {
+//
+using namespace std;
+
+//----------------------------------------------------------------------------
+// definitions
+//----------------------------------------------------------------------------
+
+enum FileType { C_TYPE = 0, JAVA_TYPE = 1, SHARP_TYPE = 2 };
+
+/* The enums below are not recognized by 'vectors' in Microsoft Visual C++
+ V5 when they are part of a namespace!!! Use Visual C++ V6 or higher.
+*/
+enum FormatStyle
+{
+ STYLE_NONE,
+ STYLE_ALLMAN,
+ STYLE_JAVA,
+ STYLE_KR,
+ STYLE_STROUSTRUP,
+ STYLE_WHITESMITH,
+ STYLE_VTK,
+ STYLE_BANNER,
+ STYLE_GNU,
+ STYLE_LINUX,
+ STYLE_HORSTMANN,
+ STYLE_1TBS,
+ STYLE_GOOGLE,
+ STYLE_MOZILLA,
+ STYLE_PICO,
+ STYLE_LISP
+};
+
+enum BraceMode
+{
+ NONE_MODE,
+ ATTACH_MODE,
+ BREAK_MODE,
+ LINUX_MODE,
+ RUN_IN_MODE // broken braces
+};
+
+// maximun value for int is 16,384 (total value of 32,767)
+enum BraceType
+{
+ NULL_TYPE = 0,
+ NAMESPACE_TYPE = 1, // also a DEFINITION_TYPE
+ CLASS_TYPE = 2, // also a DEFINITION_TYPE
+ STRUCT_TYPE = 4, // also a DEFINITION_TYPE
+ INTERFACE_TYPE = 8, // also a DEFINITION_TYPE
+ DEFINITION_TYPE = 16,
+ COMMAND_TYPE = 32,
+ ARRAY_NIS_TYPE = 64, // also an ARRAY_TYPE
+ ENUM_TYPE = 128, // also an ARRAY_TYPE
+ INIT_TYPE = 256, // also an ARRAY_TYPE
+ ARRAY_TYPE = 512,
+ EXTERN_TYPE = 1024, // extern "C", not a command type extern
+ EMPTY_BLOCK_TYPE = 2048, // also a SINGLE_LINE_TYPE
+ BREAK_BLOCK_TYPE = 4096, // also a SINGLE_LINE_TYPE
+ SINGLE_LINE_TYPE = 8192
+};
+
+enum MinConditional
+{
+ MINCOND_ZERO,
+ MINCOND_ONE,
+ MINCOND_TWO,
+ MINCOND_ONEHALF,
+ MINCOND_END
+};
+
+enum ObjCColonPad
+{
+ COLON_PAD_NO_CHANGE,
+ COLON_PAD_NONE,
+ COLON_PAD_ALL,
+ COLON_PAD_AFTER,
+ COLON_PAD_BEFORE
+};
+
+enum PointerAlign
+{
+ PTR_ALIGN_NONE,
+ PTR_ALIGN_TYPE,
+ PTR_ALIGN_MIDDLE,
+ PTR_ALIGN_NAME
+};
+
+enum ReferenceAlign
+{
+ REF_ALIGN_NONE = PTR_ALIGN_NONE,
+ REF_ALIGN_TYPE = PTR_ALIGN_TYPE,
+ REF_ALIGN_MIDDLE = PTR_ALIGN_MIDDLE,
+ REF_ALIGN_NAME = PTR_ALIGN_NAME,
+ REF_SAME_AS_PTR
+};
+
+enum FileEncoding
+{
+ ENCODING_8BIT,
+ UTF_16BE,
+ UTF_16LE, // Windows default
+ UTF_32BE,
+ UTF_32LE
+};
+
+enum LineEndFormat
+{
+ LINEEND_DEFAULT, // Use line break that matches most of the file
+ LINEEND_WINDOWS,
+ LINEEND_LINUX,
+ LINEEND_MACOLD,
+ LINEEND_CRLF = LINEEND_WINDOWS,
+ LINEEND_LF = LINEEND_LINUX,
+ LINEEND_CR = LINEEND_MACOLD
+};
+
+//-----------------------------------------------------------------------------
+// Class ASSourceIterator
+// A pure virtual class is used by ASFormatter and ASBeautifier instead of
+// ASStreamIterator. This allows programs using AStyle as a plug-in to define
+// their own ASStreamIterator. The ASStreamIterator class must inherit
+// this class.
+//-----------------------------------------------------------------------------
+
+class ASSourceIterator
+{
+public:
+ ASSourceIterator() {}
+ virtual ~ASSourceIterator() {}
+ virtual int getStreamLength() const = 0;
+ virtual bool hasMoreLines() const = 0;
+ virtual string nextLine(bool emptyLineWasDeleted = false) = 0;
+ virtual string peekNextLine() = 0;
+ virtual void peekReset() = 0;
+ virtual streamoff tellg() = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Class ASPeekStream
+// A small class using RAII to peek ahead in the ASSourceIterator stream
+// and to reset the ASSourceIterator pointer in the destructor.
+// It enables a return from anywhere in the method.
+//-----------------------------------------------------------------------------
+
+class ASPeekStream
+{
+private:
+ ASSourceIterator* sourceIterator;
+ bool needReset; // reset sourceIterator to the original position
+
+public:
+ explicit ASPeekStream(ASSourceIterator* sourceIterator_)
+ { sourceIterator = sourceIterator_; needReset = false; }
+
+ ~ASPeekStream()
+ { if (needReset) sourceIterator->peekReset(); }
+
+ bool hasMoreLines() const
+ { return sourceIterator->hasMoreLines(); }
+
+ string peekNextLine()
+ { needReset = true; return sourceIterator->peekNextLine(); }
+};
+
+
+//-----------------------------------------------------------------------------
+// Class ASResource
+//-----------------------------------------------------------------------------
+
+class ASResource
+{
+public:
+ void buildAssignmentOperators(vector<const string*>* assignmentOperators);
+ void buildCastOperators(vector<const string*>* castOperators);
+ void buildHeaders(vector<const string*>* headers, int fileType, bool beautifier = false);
+ void buildIndentableMacros(vector<const pair<const string, const string>* >* indentableMacros);
+ void buildIndentableHeaders(vector<const string*>* indentableHeaders);
+ void buildNonAssignmentOperators(vector<const string*>* nonAssignmentOperators);
+ void buildNonParenHeaders(vector<const string*>* nonParenHeaders, int fileType, bool beautifier = false);
+ void buildOperators(vector<const string*>* operators, int fileType);
+ void buildPreBlockStatements(vector<const string*>* preBlockStatements, int fileType);
+ void buildPreCommandHeaders(vector<const string*>* preCommandHeaders, int fileType);
+ void buildPreDefinitionHeaders(vector<const string*>* preDefinitionHeaders, int fileType);
+
+public:
+ static const string AS_IF, AS_ELSE;
+ static const string AS_DO, AS_WHILE;
+ static const string AS_FOR;
+ static const string AS_SWITCH, AS_CASE, AS_DEFAULT;
+ static const string AS_TRY, AS_CATCH, AS_THROW, AS_THROWS, AS_FINALLY, AS_USING;
+ static const string _AS_TRY, _AS_FINALLY, _AS_EXCEPT;
+ static const string AS_PUBLIC, AS_PROTECTED, AS_PRIVATE;
+ static const string AS_CLASS, AS_STRUCT, AS_UNION, AS_INTERFACE, AS_NAMESPACE;
+ static const string AS_MODULE;
+ static const string AS_END;
+ static const string AS_SELECTOR;
+ static const string AS_EXTERN, AS_ENUM;
+ static const string AS_STATIC, AS_CONST, AS_SEALED, AS_OVERRIDE, AS_VOLATILE, AS_NEW, AS_DELETE;
+ static const string AS_NOEXCEPT, AS_INTERRUPT, AS_AUTORELEASEPOOL;
+ static const string AS_WHERE, AS_LET, AS_SYNCHRONIZED;
+ static const string AS_OPERATOR, AS_TEMPLATE;
+ static const string AS_OPEN_BRACE, AS_CLOSE_BRACE;
+ static const string AS_OPEN_LINE_COMMENT, AS_OPEN_COMMENT, AS_CLOSE_COMMENT;
+ static const string AS_BAR_DEFINE, AS_BAR_INCLUDE, AS_BAR_IF, AS_BAR_EL, AS_BAR_ENDIF;
+ static const string AS_AUTO, AS_RETURN;
+ static const string AS_CIN, AS_COUT, AS_CERR;
+ static const string AS_ASSIGN, AS_PLUS_ASSIGN, AS_MINUS_ASSIGN, AS_MULT_ASSIGN;
+ static const string AS_DIV_ASSIGN, AS_MOD_ASSIGN, AS_XOR_ASSIGN, AS_OR_ASSIGN, AS_AND_ASSIGN;
+ static const string AS_GR_GR_ASSIGN, AS_LS_LS_ASSIGN, AS_GR_GR_GR_ASSIGN, AS_LS_LS_LS_ASSIGN;
+ static const string AS_GCC_MIN_ASSIGN, AS_GCC_MAX_ASSIGN;
+ static const string AS_EQUAL, AS_PLUS_PLUS, AS_MINUS_MINUS, AS_NOT_EQUAL, AS_GR_EQUAL;
+ static const string AS_LS_EQUAL, AS_LS_LS_LS, AS_LS_LS, AS_GR_GR_GR, AS_GR_GR;
+ static const string AS_QUESTION_QUESTION, AS_LAMBDA;
+ static const string AS_ARROW, AS_AND, AS_OR;
+ static const string AS_SCOPE_RESOLUTION;
+ static const string AS_PLUS, AS_MINUS, AS_MULT, AS_DIV, AS_MOD, AS_GR, AS_LS;
+ static const string AS_NOT, AS_BIT_XOR, AS_BIT_OR, AS_BIT_AND, AS_BIT_NOT;
+ static const string AS_QUESTION, AS_COLON, AS_SEMICOLON, AS_COMMA;
+ static const string AS_ASM, AS__ASM__, AS_MS_ASM, AS_MS__ASM;
+ static const string AS_QFOREACH, AS_QFOREVER, AS_FOREVER;
+ static const string AS_FOREACH, AS_LOCK, AS_UNSAFE, AS_FIXED;
+ static const string AS_GET, AS_SET, AS_ADD, AS_REMOVE;
+ static const string AS_DELEGATE, AS_UNCHECKED;
+ static const string AS_CONST_CAST, AS_DYNAMIC_CAST, AS_REINTERPRET_CAST, AS_STATIC_CAST;
+ static const string AS_NS_DURING, AS_NS_HANDLER;
+}; // Class ASResource
+
+//-----------------------------------------------------------------------------
+// Class ASBase
+// Functions definitions are at the end of ASResource.cpp.
+//-----------------------------------------------------------------------------
+
+class ASBase : protected ASResource
+{
+private:
+ // all variables should be set by the "init" function
+ int baseFileType; // a value from enum FileType
+
+protected:
+ ASBase() : baseFileType(C_TYPE) { }
+
+protected: // inline functions
+ void init(int fileTypeArg) { baseFileType = fileTypeArg; }
+ bool isCStyle() const { return (baseFileType == C_TYPE); }
+ bool isJavaStyle() const { return (baseFileType == JAVA_TYPE); }
+ bool isSharpStyle() const { return (baseFileType == SHARP_TYPE); }
+ bool isWhiteSpace(char ch) const { return (ch == ' ' || ch == '\t'); }
+
+protected: // functions definitions are at the end of ASResource.cpp
+ const string* findHeader(const string& line, int i,
+ const vector<const string*>* possibleHeaders) const;
+ bool findKeyword(const string& line, int i, const string& keyword) const;
+ const string* findOperator(const string& line, int i,
+ const vector<const string*>* possibleOperators) const;
+ string getCurrentWord(const string& line, size_t index) const;
+ bool isDigit(char ch) const;
+ bool isLegalNameChar(char ch) const;
+ bool isCharPotentialHeader(const string& line, size_t i) const;
+ bool isCharPotentialOperator(char ch) const;
+ bool isDigitSeparator(const string& line, int i) const;
+ char peekNextChar(const string& line, int i) const;
+
+}; // Class ASBase
+
+//-----------------------------------------------------------------------------
+// Class ASBeautifier
+//-----------------------------------------------------------------------------
+
+class ASBeautifier : protected ASBase
+{
+public:
+ ASBeautifier();
+ virtual ~ASBeautifier();
+ virtual void init(ASSourceIterator* iter);
+ virtual string beautify(const string& originalLine);
+ void setCaseIndent(bool state);
+ void setClassIndent(bool state);
+ void setContinuationIndentation(int indent = 1);
+ void setCStyle();
+ void setDefaultTabLength();
+ void setEmptyLineFill(bool state);
+ void setForceTabXIndentation(int length);
+ void setAfterParenIndent(bool state);
+ void setJavaStyle();
+ void setLabelIndent(bool state);
+ void setMaxContinuationIndentLength(int max);
+ void setMaxInStatementIndentLength(int max);
+ void setMinConditionalIndentOption(int min);
+ void setMinConditionalIndentLength();
+ void setModeManuallySet(bool state);
+ void setModifierIndent(bool state);
+ void setNamespaceIndent(bool state);
+ void setAlignMethodColon(bool state);
+ void setSharpStyle();
+ void setSpaceIndentation(int length = 4);
+ void setSwitchIndent(bool state);
+ void setTabIndentation(int length = 4, bool forceTabs = false);
+ void setPreprocDefineIndent(bool state);
+ void setPreprocConditionalIndent(bool state);
+ int getBeautifierFileType() const;
+ int getFileType() const;
+ int getIndentLength() const;
+ int getTabLength() const;
+ string getIndentString() const;
+ string getNextWord(const string& line, size_t currPos) const;
+ bool getAlignMethodColon() const;
+ bool getBraceIndent() const;
+ bool getBlockIndent() const;
+ bool getCaseIndent() const;
+ bool getClassIndent() const;
+ bool getEmptyLineFill() const;
+ bool getForceTabIndentation() const;
+ bool getModeManuallySet() const;
+ bool getModifierIndent() const;
+ bool getNamespaceIndent() const;
+ bool getPreprocDefineIndent() const;
+ bool getSwitchIndent() const;
+
+protected:
+ void deleteBeautifierVectors();
+ int getNextProgramCharDistance(const string& line, int i) const;
+ int indexOf(const vector<const string*>& container, const string* element) const;
+ void setBlockIndent(bool state);
+ void setBraceIndent(bool state);
+ void setBraceIndentVtk(bool state);
+ string extractPreprocessorStatement(const string& line) const;
+ string trim(const string& str) const;
+ string rtrim(const string& str) const;
+
+ // variables set by ASFormatter - must be updated in activeBeautifierStack
+ int inLineNumber;
+ int runInIndentContinuation;
+ int nonInStatementBrace;
+ int objCColonAlignSubsequent; // for subsequent lines not counting indent
+ bool lineCommentNoBeautify;
+ bool isElseHeaderIndent;
+ bool isCaseHeaderCommentIndent;
+ bool isNonInStatementArray;
+ bool isSharpAccessor;
+ bool isSharpDelegate;
+ bool isInExternC;
+ bool isInBeautifySQL;
+ bool isInIndentableStruct;
+ bool isInIndentablePreproc;
+
+private: // functions
+ ASBeautifier(const ASBeautifier& other); // inline functions
+ ASBeautifier& operator=(ASBeautifier&); // not to be implemented
+
+ void adjustObjCMethodDefinitionIndentation(const string& line_);
+ void adjustObjCMethodCallIndentation(const string& line_);
+ void adjustParsedLineIndentation(size_t iPrelim, bool isInExtraHeaderIndent);
+ void computePreliminaryIndentation();
+ void parseCurrentLine(const string& line);
+ void popLastContinuationIndent();
+ void processPreprocessor(const string& preproc, const string& line);
+ void registerContinuationIndent(const string& line, int i, int spaceIndentCount_,
+ int tabIncrementIn, int minIndent, bool updateParenStack);
+ void registerContinuationIndentColon(const string& line, int i, int tabIncrementIn);
+ void initVectors();
+ void initTempStacksContainer(vector<vector<const string*>*>*& container,
+ vector<vector<const string*>*>* value);
+ void clearObjCMethodDefinitionAlignment();
+ void deleteBeautifierContainer(vector<ASBeautifier*>*& container);
+ void deleteTempStacksContainer(vector<vector<const string*>*>*& container);
+ int adjustIndentCountForBreakElseIfComments() const;
+ int computeObjCColonAlignment(const string& line, int colonAlignPosition) const;
+ int convertTabToSpaces(int i, int tabIncrementIn) const;
+ int getContinuationIndentAssign(const string& line, size_t currPos) const;
+ int getContinuationIndentComma(const string& line, size_t currPos) const;
+ int getObjCFollowingKeyword(const string& line, int bracePos) const;
+ bool isIndentedPreprocessor(const string& line, size_t currPos) const;
+ bool isLineEndComment(const string& line, int startPos) const;
+ bool isPreprocessorConditionalCplusplus(const string& line) const;
+ bool isInPreprocessorUnterminatedComment(const string& line);
+ bool statementEndsWithComma(const string& line, int index) const;
+ const string& getIndentedLineReturn(const string& newLine, const string& originalLine) const;
+ string getIndentedSpaceEquivalent(const string& line_) const;
+ string preLineWS(int lineIndentCount, int lineSpaceIndentCount) const;
+ template<typename T> void deleteContainer(T& container);
+ template<typename T> void initContainer(T& container, T value);
+ vector<vector<const string*>*>* copyTempStacks(const ASBeautifier& other) const;
+ pair<int, int> computePreprocessorIndent();
+
+private: // variables
+ int beautifierFileType;
+ vector<const string*>* headers;
+ vector<const string*>* nonParenHeaders;
+ vector<const string*>* preBlockStatements;
+ vector<const string*>* preCommandHeaders;
+ vector<const string*>* assignmentOperators;
+ vector<const string*>* nonAssignmentOperators;
+ vector<const string*>* indentableHeaders;
+
+ vector<ASBeautifier*>* waitingBeautifierStack;
+ vector<ASBeautifier*>* activeBeautifierStack;
+ vector<int>* waitingBeautifierStackLengthStack;
+ vector<int>* activeBeautifierStackLengthStack;
+ vector<const string*>* headerStack;
+ vector<vector<const string*>* >* tempStacks;
+ vector<int>* squareBracketDepthStack;
+ vector<bool>* blockStatementStack;
+ vector<bool>* parenStatementStack;
+ vector<bool>* braceBlockStateStack;
+ vector<int>* continuationIndentStack;
+ vector<int>* continuationIndentStackSizeStack;
+ vector<int>* parenIndentStack;
+ vector<pair<int, int> >* preprocIndentStack;
+
+ ASSourceIterator* sourceIterator;
+ const string* currentHeader;
+ const string* previousLastLineHeader;
+ const string* probationHeader;
+ const string* lastLineHeader;
+ string indentString;
+ string verbatimDelimiter;
+ bool isInQuote;
+ bool isInVerbatimQuote;
+ bool haveLineContinuationChar;
+ bool isInAsm;
+ bool isInAsmOneLine;
+ bool isInAsmBlock;
+ bool isInComment;
+ bool isInPreprocessorComment;
+ bool isInRunInComment;
+ bool isInCase;
+ bool isInQuestion;
+ bool isContinuation;
+ bool isInHeader;
+ bool isInTemplate;
+ bool isInDefine;
+ bool isInDefineDefinition;
+ bool classIndent;
+ bool isIndentModeOff;
+ bool isInClassHeader; // is in a class before the opening brace
+ bool isInClassHeaderTab; // is in an indentable class header line
+ bool isInClassInitializer; // is in a class after the ':' initializer
+ bool isInClass; // is in a class after the opening brace
+ bool isInObjCMethodDefinition;
+ bool isInObjCMethodCall;
+ bool isInObjCMethodCallFirst;
+ bool isImmediatelyPostObjCMethodDefinition;
+ bool isImmediatelyPostObjCMethodCall;
+ bool isInIndentablePreprocBlock;
+ bool isInObjCInterface;
+ bool isInEnum;
+ bool isInEnumTypeID;
+ bool isInLet;
+ bool modifierIndent;
+ bool switchIndent;
+ bool caseIndent;
+ bool namespaceIndent;
+ bool blockIndent;
+ bool braceIndent;
+ bool braceIndentVtk;
+ bool shouldIndentAfterParen;
+ bool labelIndent;
+ bool shouldIndentPreprocDefine;
+ bool isInConditional;
+ bool isModeManuallySet;
+ bool shouldForceTabIndentation;
+ bool emptyLineFill;
+ bool backslashEndsPrevLine;
+ bool lineOpensWithLineComment;
+ bool lineOpensWithComment;
+ bool lineStartsInComment;
+ bool blockCommentNoIndent;
+ bool blockCommentNoBeautify;
+ bool previousLineProbationTab;
+ bool lineBeginsWithOpenBrace;
+ bool lineBeginsWithCloseBrace;
+ bool lineBeginsWithComma;
+ bool lineIsCommentOnly;
+ bool lineIsLineCommentOnly;
+ bool shouldIndentBracedLine;
+ bool isInSwitch;
+ bool foundPreCommandHeader;
+ bool foundPreCommandMacro;
+ bool shouldAlignMethodColon;
+ bool shouldIndentPreprocConditional;
+ int indentCount;
+ int spaceIndentCount;
+ int spaceIndentObjCMethodAlignment;
+ int bracePosObjCMethodAlignment;
+ int colonIndentObjCMethodAlignment;
+ int lineOpeningBlocksNum;
+ int lineClosingBlocksNum;
+ int fileType;
+ int minConditionalOption;
+ int minConditionalIndent;
+ int parenDepth;
+ int indentLength;
+ int tabLength;
+ int continuationIndent;
+ int blockTabCount;
+ int maxContinuationIndent;
+ int classInitializerIndents;
+ int templateDepth;
+ int squareBracketCount;
+ int prevFinalLineSpaceIndentCount;
+ int prevFinalLineIndentCount;
+ int defineIndentCount;
+ int preprocBlockIndent;
+ char quoteChar;
+ char prevNonSpaceCh;
+ char currentNonSpaceCh;
+ char currentNonLegalCh;
+ char prevNonLegalCh;
+}; // Class ASBeautifier
+
+//-----------------------------------------------------------------------------
+// Class ASEnhancer
+//-----------------------------------------------------------------------------
+
+class ASEnhancer : protected ASBase
+{
+public: // functions
+ ASEnhancer();
+ virtual ~ASEnhancer();
+ void init(int, int, int, bool, bool, bool, bool, bool, bool, bool,
+ vector<const pair<const string, const string>* >*);
+ void enhance(string& line, bool isInNamespace, bool isInPreprocessor, bool isInSQL);
+
+private: // functions
+ void convertForceTabIndentToSpaces(string& line) const;
+ void convertSpaceIndentToForceTab(string& line) const;
+ size_t findCaseColon(const string& line, size_t caseIndex) const;
+ int indentLine(string& line, int indent) const;
+ bool isBeginDeclareSectionSQL(const string& line, size_t index) const;
+ bool isEndDeclareSectionSQL(const string& line, size_t index) const;
+ bool isOneLineBlockReached(const string& line, int startChar) const;
+ void parseCurrentLine(string& line, bool isInPreprocessor, bool isInSQL);
+ size_t processSwitchBlock(string& line, size_t index);
+ int unindentLine(string& line, int unindent) const;
+
+private:
+ // options from command line or options file
+ int indentLength;
+ int tabLength;
+ bool useTabs;
+ bool forceTab;
+ bool namespaceIndent;
+ bool caseIndent;
+ bool preprocBlockIndent;
+ bool preprocDefineIndent;
+ bool emptyLineFill;
+
+ // parsing variables
+ int lineNumber;
+ bool isInQuote;
+ bool isInComment;
+ char quoteChar;
+
+ // unindent variables
+ int braceCount;
+ int switchDepth;
+ int eventPreprocDepth;
+ bool lookingForCaseBrace;
+ bool unindentNextLine;
+ bool shouldUnindentLine;
+ bool shouldUnindentComment;
+
+ // struct used by ParseFormattedLine function
+ // contains variables used to unindent the case blocks
+ struct SwitchVariables
+ {
+ int switchBraceCount;
+ int unindentDepth;
+ bool unindentCase;
+ };
+
+ SwitchVariables sw; // switch variables struct
+ vector<SwitchVariables> switchStack; // stack vector of switch variables
+
+ // event table variables
+ bool nextLineIsEventIndent; // begin event table indent is reached
+ bool isInEventTable; // need to indent an event table
+ vector<const pair<const string, const string>* >* indentableMacros;
+
+ // SQL variables
+ bool nextLineIsDeclareIndent; // begin declare section indent is reached
+ bool isInDeclareSection; // need to indent a declare section
+
+}; // Class ASEnhancer
+
+//-----------------------------------------------------------------------------
+// Class ASFormatter
+//-----------------------------------------------------------------------------
+
+class ASFormatter : public ASBeautifier
+{
+public: // functions
+ ASFormatter();
+ virtual ~ASFormatter();
+ virtual void init(ASSourceIterator* si);
+ virtual bool hasMoreLines() const;
+ virtual string nextLine();
+ LineEndFormat getLineEndFormat() const;
+ bool getIsLineReady() const;
+ void setFormattingStyle(FormatStyle style);
+ void setAddBracesMode(bool state);
+ void setAddOneLineBracesMode(bool state);
+ void setRemoveBracesMode(bool state);
+ void setAttachClass(bool state);
+ void setAttachClosingWhile(bool state);
+ void setAttachExternC(bool state);
+ void setAttachNamespace(bool state);
+ void setAttachInline(bool state);
+ void setBraceFormatMode(BraceMode mode);
+ void setBreakAfterMode(bool state);
+ void setBreakClosingHeaderBracesMode(bool state);
+ void setBreakBlocksMode(bool state);
+ void setBreakClosingHeaderBlocksMode(bool state);
+ void setBreakElseIfsMode(bool state);
+ void setBreakOneLineBlocksMode(bool state);
+ void setBreakOneLineHeadersMode(bool state);
+ void setBreakOneLineStatementsMode(bool state);
+ void setMethodPrefixPaddingMode(bool state);
+ void setMethodPrefixUnPaddingMode(bool state);
+ void setReturnTypePaddingMode(bool state);
+ void setReturnTypeUnPaddingMode(bool state);
+ void setParamTypePaddingMode(bool state);
+ void setParamTypeUnPaddingMode(bool state);
+ void setCloseTemplatesMode(bool state);
+ void setCommaPaddingMode(bool state);
+ void setDeleteEmptyLinesMode(bool state);
+ void setIndentCol1CommentsMode(bool state);
+ void setLineEndFormat(LineEndFormat fmt);
+ void setMaxCodeLength(int max);
+ void setObjCColonPaddingMode(ObjCColonPad mode);
+ void setOperatorPaddingMode(bool state);
+ void setParensOutsidePaddingMode(bool state);
+ void setParensFirstPaddingMode(bool state);
+ void setParensInsidePaddingMode(bool state);
+ void setParensHeaderPaddingMode(bool state);
+ void setParensUnPaddingMode(bool state);
+ void setPointerAlignment(PointerAlign alignment);
+ void setPreprocBlockIndent(bool state);
+ void setReferenceAlignment(ReferenceAlign alignment);
+ void setStripCommentPrefix(bool state);
+ void setTabSpaceConversionMode(bool state);
+ size_t getChecksumIn() const;
+ size_t getChecksumOut() const;
+ int getChecksumDiff() const;
+ int getFormatterFileType() const;
+ // retained for compatability with release 2.06
+ // "Brackets" have been changed to "Braces" in 3.0
+ // they are referenced only by the old "bracket" options
+ void setAddBracketsMode(bool state);
+ void setAddOneLineBracketsMode(bool state);
+ void setRemoveBracketsMode(bool state);
+ void setBreakClosingHeaderBracketsMode(bool state);
+
+
+private: // functions
+ ASFormatter(const ASFormatter& copy); // not to be implemented
+ ASFormatter& operator=(ASFormatter&); // not to be implemented
+ template<typename T> void deleteContainer(T& container);
+ template<typename T> void initContainer(T& container, T value);
+ char peekNextChar() const;
+ BraceType getBraceType();
+ bool adjustChecksumIn(int adjustment);
+ bool computeChecksumIn(const string& currentLine_);
+ bool computeChecksumOut(const string& beautifiedLine);
+ bool addBracesToStatement();
+ bool removeBracesFromStatement();
+ bool commentAndHeaderFollows();
+ bool getNextChar();
+ bool getNextLine(bool emptyLineWasDeleted = false);
+ bool isArrayOperator() const;
+ bool isBeforeComment() const;
+ bool isBeforeAnyComment() const;
+ bool isBeforeAnyLineEndComment(int startPos) const;
+ bool isBeforeMultipleLineEndComments(int startPos) const;
+ bool isBraceType(BraceType a, BraceType b) const;
+ bool isClassInitializer() const;
+ bool isClosingHeader(const string* header) const;
+ bool isCurrentBraceBroken() const;
+ bool isDereferenceOrAddressOf() const;
+ bool isExecSQL(const string& line, size_t index) const;
+ bool isEmptyLine(const string& line) const;
+ bool isExternC() const;
+ bool isMultiStatementLine() const;
+ bool isNextWordSharpNonParenHeader(int startChar) const;
+ bool isNonInStatementArrayBrace() const;
+ bool isOkToSplitFormattedLine();
+ bool isPointerOrReference() const;
+ bool isPointerOrReferenceCentered() const;
+ bool isPointerOrReferenceVariable(const string& word) const;
+ bool isSharpStyleWithParen(const string* header) const;
+ bool isStructAccessModified(const string& firstLine, size_t index) const;
+ bool isIndentablePreprocessorBlock(const string& firstLine, size_t index);
+ bool isNDefPreprocStatement(const string& nextLine_, const string& preproc) const;
+ bool isUnaryOperator() const;
+ bool isUniformInitializerBrace() const;
+ bool isImmediatelyPostCast() const;
+ bool isInExponent() const;
+ bool isInSwitchStatement() const;
+ bool isNextCharOpeningBrace(int startChar) const;
+ bool isOkToBreakBlock(BraceType braceType) const;
+ bool isOperatorPaddingDisabled() const;
+ bool pointerSymbolFollows() const;
+ int findObjCColonAlignment() const;
+ int getCurrentLineCommentAdjustment();
+ int getNextLineCommentAdjustment();
+ int isOneLineBlockReached(const string& line, int startChar) const;
+ void adjustComments();
+ void appendChar(char ch, bool canBreakLine);
+ void appendCharInsideComments();
+ void appendClosingHeader();
+ void appendOperator(const string& sequence, bool canBreakLine = true);
+ void appendSequence(const string& sequence, bool canBreakLine = true);
+ void appendSpacePad();
+ void appendSpaceAfter();
+ void breakLine(bool isSplitLine = false);
+ void buildLanguageVectors();
+ void updateFormattedLineSplitPoints(char appendedChar);
+ void updateFormattedLineSplitPointsOperator(const string& sequence);
+ void checkIfTemplateOpener();
+ void clearFormattedLineSplitPoints();
+ void convertTabToSpaces();
+ void deleteContainer(vector<BraceType>*& container);
+ void formatArrayRunIn();
+ void formatRunIn();
+ void formatArrayBraces(BraceType braceType, bool isOpeningArrayBrace);
+ void formatClosingBrace(BraceType braceType);
+ void formatCommentBody();
+ void formatCommentOpener();
+ void formatCommentCloser();
+ void formatLineCommentBody();
+ void formatLineCommentOpener();
+ void formatOpeningBrace(BraceType braceType);
+ void formatQuoteBody();
+ void formatQuoteOpener();
+ void formatPointerOrReference();
+ void formatPointerOrReferenceCast();
+ void formatPointerOrReferenceToMiddle();
+ void formatPointerOrReferenceToName();
+ void formatPointerOrReferenceToType();
+ void fixOptionVariableConflicts();
+ void goForward(int i);
+ void isLineBreakBeforeClosingHeader();
+ void initContainer(vector<BraceType>*& container, vector<BraceType>* value);
+ void initNewLine();
+ void padObjCMethodColon();
+ void padObjCMethodPrefix();
+ void padObjCParamType();
+ void padObjCReturnType();
+ void padOperators(const string* newOperator);
+ void padParens();
+ void processPreprocessor();
+ void resetEndOfStatement();
+ void setAttachClosingBraceMode(bool state);
+ void stripCommentPrefix();
+ void testForTimeToSplitFormattedLine();
+ void trimContinuationLine();
+ void updateFormattedLineSplitPointsPointerOrReference(size_t index);
+ size_t findFormattedLineSplitPoint() const;
+ size_t findNextChar(const string& line, char searchChar, int searchStart = 0) const;
+ const string* checkForHeaderFollowingComment(const string& firstLine) const;
+ const string* getFollowingOperator() const;
+ string getPreviousWord(const string& line, int currPos) const;
+ string peekNextText(const string& firstLine,
+ bool endOnEmptyLine = false,
+ shared_ptr<ASPeekStream> streamArg = nullptr) const;
+
+private: // variables
+ int formatterFileType;
+ vector<const string*>* headers;
+ vector<const string*>* nonParenHeaders;
+ vector<const string*>* preDefinitionHeaders;
+ vector<const string*>* preCommandHeaders;
+ vector<const string*>* operators;
+ vector<const string*>* assignmentOperators;
+ vector<const string*>* castOperators;
+ vector<const pair<const string, const string>* >* indentableMacros; // for ASEnhancer
+
+ ASSourceIterator* sourceIterator;
+ ASEnhancer* enhancer;
+
+ vector<const string*>* preBraceHeaderStack;
+ vector<BraceType>* braceTypeStack;
+ vector<int>* parenStack;
+ vector<bool>* structStack;
+ vector<bool>* questionMarkStack;
+
+ string currentLine;
+ string formattedLine;
+ string readyFormattedLine;
+ string verbatimDelimiter;
+ const string* currentHeader;
+ char currentChar;
+ char previousChar;
+ char previousNonWSChar;
+ char previousCommandChar;
+ char quoteChar;
+ streamoff preprocBlockEnd;
+ int charNum;
+ int runInIndentChars;
+ int nextLineSpacePadNum;
+ int objCColonAlign;
+ int preprocBraceTypeStackSize;
+ int spacePadNum;
+ int tabIncrementIn;
+ int templateDepth;
+ int squareBracketCount;
+ size_t checksumIn;
+ size_t checksumOut;
+ size_t currentLineFirstBraceNum; // first brace location on currentLine
+ size_t formattedLineCommentNum; // comment location on formattedLine
+ size_t leadingSpaces;
+ size_t maxCodeLength;
+
+ // possible split points
+ size_t maxSemi; // probably a 'for' statement
+ size_t maxAndOr; // probably an 'if' statement
+ size_t maxComma;
+ size_t maxParen;
+ size_t maxWhiteSpace;
+ size_t maxSemiPending;
+ size_t maxAndOrPending;
+ size_t maxCommaPending;
+ size_t maxParenPending;
+ size_t maxWhiteSpacePending;
+
+ size_t previousReadyFormattedLineLength;
+ FormatStyle formattingStyle;
+ BraceMode braceFormatMode;
+ BraceType previousBraceType;
+ PointerAlign pointerAlignment;
+ ReferenceAlign referenceAlignment;
+ ObjCColonPad objCColonPadMode;
+ LineEndFormat lineEnd;
+ bool isVirgin;
+ bool isInVirginLine;
+ bool shouldPadCommas;
+ bool shouldPadOperators;
+ bool shouldPadParensOutside;
+ bool shouldPadFirstParen;
+ bool shouldPadParensInside;
+ bool shouldPadHeader;
+ bool shouldStripCommentPrefix;
+ bool shouldUnPadParens;
+ bool shouldConvertTabs;
+ bool shouldIndentCol1Comments;
+ bool shouldIndentPreprocBlock;
+ bool shouldCloseTemplates;
+ bool shouldAttachExternC;
+ bool shouldAttachNamespace;
+ bool shouldAttachClass;
+ bool shouldAttachClosingWhile;
+ bool shouldAttachInline;
+ bool isInLineComment;
+ bool isInComment;
+ bool isInCommentStartLine;
+ bool noTrimCommentContinuation;
+ bool isInPreprocessor;
+ bool isInPreprocessorBeautify;
+ bool isInTemplate;
+ bool doesLineStartComment;
+ bool lineEndsInCommentOnly;
+ bool lineIsCommentOnly;
+ bool lineIsLineCommentOnly;
+ bool lineIsEmpty;
+ bool isImmediatelyPostCommentOnly;
+ bool isImmediatelyPostEmptyLine;
+ bool isInClassInitializer;
+ bool isInQuote;
+ bool isInVerbatimQuote;
+ bool haveLineContinuationChar;
+ bool isInQuoteContinuation;
+ bool isHeaderInMultiStatementLine;
+ bool isSpecialChar;
+ bool isNonParenHeader;
+ bool foundQuestionMark;
+ bool foundPreDefinitionHeader;
+ bool foundNamespaceHeader;
+ bool foundClassHeader;
+ bool foundStructHeader;
+ bool foundInterfaceHeader;
+ bool foundPreCommandHeader;
+ bool foundPreCommandMacro;
+ bool foundTrailingReturnType;
+ bool foundCastOperator;
+ bool isInLineBreak;
+ bool endOfAsmReached;
+ bool endOfCodeReached;
+ bool lineCommentNoIndent;
+ bool isFormattingModeOff;
+ bool isInEnum;
+ bool isInExecSQL;
+ bool isInAsm;
+ bool isInAsmOneLine;
+ bool isInAsmBlock;
+ bool isLineReady;
+ bool elseHeaderFollowsComments;
+ bool caseHeaderFollowsComments;
+ bool isPreviousBraceBlockRelated;
+ bool isInPotentialCalculation;
+ bool isCharImmediatelyPostComment;
+ bool isPreviousCharPostComment;
+ bool isCharImmediatelyPostLineComment;
+ bool isCharImmediatelyPostOpenBlock;
+ bool isCharImmediatelyPostCloseBlock;
+ bool isCharImmediatelyPostTemplate;
+ bool isCharImmediatelyPostReturn;
+ bool isCharImmediatelyPostThrow;
+ bool isCharImmediatelyPostNewDelete;
+ bool isCharImmediatelyPostOperator;
+ bool isCharImmediatelyPostPointerOrReference;
+ bool isInObjCMethodDefinition;
+ bool isInObjCInterface;
+ bool isInObjCReturnType;
+ bool isInObjCSelector;
+ bool breakCurrentOneLineBlock;
+ bool shouldRemoveNextClosingBrace;
+ bool isInBraceRunIn;
+ bool currentLineBeginsWithBrace;
+ bool attachClosingBraceMode;
+ bool shouldBreakOneLineBlocks;
+ bool shouldBreakOneLineHeaders;
+ bool shouldBreakOneLineStatements;
+ bool shouldBreakClosingHeaderBraces;
+ bool shouldBreakElseIfs;
+ bool shouldBreakLineAfterLogical;
+ bool shouldAddBraces;
+ bool shouldAddOneLineBraces;
+ bool shouldRemoveBraces;
+ bool shouldPadMethodColon;
+ bool shouldPadMethodPrefix;
+ bool shouldReparseCurrentChar;
+ bool shouldUnPadMethodPrefix;
+ bool shouldPadReturnType;
+ bool shouldUnPadReturnType;
+ bool shouldPadParamType;
+ bool shouldUnPadParamType;
+ bool shouldDeleteEmptyLines;
+ bool needHeaderOpeningBrace;
+ bool shouldBreakLineAtNextChar;
+ bool shouldKeepLineUnbroken;
+ bool passedSemicolon;
+ bool passedColon;
+ bool isImmediatelyPostNonInStmt;
+ bool isCharImmediatelyPostNonInStmt;
+ bool isImmediatelyPostComment;
+ bool isImmediatelyPostLineComment;
+ bool isImmediatelyPostEmptyBlock;
+ bool isImmediatelyPostObjCMethodPrefix;
+ bool isImmediatelyPostPreprocessor;
+ bool isImmediatelyPostReturn;
+ bool isImmediatelyPostThrow;
+ bool isImmediatelyPostNewDelete;
+ bool isImmediatelyPostOperator;
+ bool isImmediatelyPostTemplate;
+ bool isImmediatelyPostPointerOrReference;
+ bool shouldBreakBlocks;
+ bool shouldBreakClosingHeaderBlocks;
+ bool isPrependPostBlockEmptyLineRequested;
+ bool isAppendPostBlockEmptyLineRequested;
+ bool isIndentableProprocessor;
+ bool isIndentableProprocessorBlock;
+ bool prependEmptyLine;
+ bool appendOpeningBrace;
+ bool foundClosingHeader;
+ bool isInHeader;
+ bool isImmediatelyPostHeader;
+ bool isInCase;
+ bool isFirstPreprocConditional;
+ bool processedFirstConditional;
+ bool isJavaStaticConstructor;
+
+private: // inline functions
+ // append the CURRENT character (curentChar) to the current formatted line.
+ void appendCurrentChar(bool canBreakLine = true)
+ { appendChar(currentChar, canBreakLine); }
+
+ // check if a specific sequence exists in the current placement of the current line
+ bool isSequenceReached(const char* sequence) const
+ { return currentLine.compare(charNum, strlen(sequence), sequence) == 0; }
+
+ // call ASBase::findHeader for the current character
+ const string* findHeader(const vector<const string*>* headers_)
+ { return ASBase::findHeader(currentLine, charNum, headers_); }
+
+ // call ASBase::findOperator for the current character
+ const string* findOperator(const vector<const string*>* operators_)
+ { return ASBase::findOperator(currentLine, charNum, operators_); }
+}; // Class ASFormatter
+
+//-----------------------------------------------------------------------------
+// astyle namespace global declarations
+//-----------------------------------------------------------------------------
+// sort comparison functions for ASResource
+bool sortOnLength(const string* a, const string* b);
+bool sortOnName(const string* a, const string* b);
+
+} // namespace astyle
+
+// end of astyle namespace --------------------------------------------------
+
+#endif // closes ASTYLE_H
--- /dev/null
+// astyle_main.cpp
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * AStyle_main source file map.
+ * This source file contains several classes.
+ * They are arranged as follows.
+ * ---------------------------------------
+ * namespace astyle {
+ * ASStreamIterator methods
+ * ASConsole methods
+ * // Windows specific
+ * // Linux specific
+ * ASLibrary methods
+ * // Windows specific
+ * // Linux specific
+ * ASOptions methods
+ * ASEncoding methods
+ * } // end of astyle namespace
+ * Global Area ---------------------------
+ * Java Native Interface functions
+ * AStyleMainUtf16 entry point
+ * AStyleMain entry point
+ * AStyleGetVersion entry point
+ * main entry point
+ * ---------------------------------------
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ */
+
+//-----------------------------------------------------------------------------
+// headers
+//-----------------------------------------------------------------------------
+
+#include "astyle_main.h"
+
+#include <algorithm>
+#include <cerrno>
+#include <clocale> // needed by some compilers
+#include <cstdlib>
+#include <fstream>
+#include <sstream>
+
+// includes for recursive getFileNames() function
+#ifdef _WIN32
+ #undef UNICODE // use ASCII windows functions
+ #include <windows.h>
+#else
+ #include <dirent.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #ifdef __VMS
+ #include <unixlib.h>
+ #include <rms.h>
+ #include <ssdef.h>
+ #include <stsdef.h>
+ #include <lib$routines.h>
+ #include <starlet.h>
+ #endif /* __VMS */
+#endif
+
+//-----------------------------------------------------------------------------
+// declarations
+//-----------------------------------------------------------------------------
+
+// turn off MinGW automatic file globbing
+// this CANNOT be in the astyle namespace
+#ifndef ASTYLE_LIB
+ int _CRT_glob = 0;
+#endif
+
+//----------------------------------------------------------------------------
+// astyle namespace
+//----------------------------------------------------------------------------
+
+namespace astyle {
+//
+// console build variables
+#ifndef ASTYLE_LIB
+ #ifdef _WIN32
+ char g_fileSeparator = '\\'; // Windows file separator
+ bool g_isCaseSensitive = false; // Windows IS NOT case sensitive
+ #else
+ char g_fileSeparator = '/'; // Linux file separator
+ bool g_isCaseSensitive = true; // Linux IS case sensitive
+ #endif // _WIN32
+#endif // ASTYLE_LIB
+
+// java library build variables
+#ifdef ASTYLE_JNI
+ JNIEnv* g_env;
+ jobject g_obj;
+ jmethodID g_mid;
+#endif
+
+const char* g_version = "3.0";
+
+//-----------------------------------------------------------------------------
+// ASStreamIterator class
+// typename will be istringstream for GUI and istream otherwise
+//-----------------------------------------------------------------------------
+
+template<typename T>
+ASStreamIterator<T>::ASStreamIterator(T* in)
+{
+ inStream = in;
+ buffer.reserve(200);
+ eolWindows = 0;
+ eolLinux = 0;
+ eolMacOld = 0;
+ peekStart = 0;
+ prevLineDeleted = false;
+ checkForEmptyLine = false;
+ // get length of stream
+ inStream->seekg(0, inStream->end);
+ streamLength = inStream->tellg();
+ inStream->seekg(0, inStream->beg);
+}
+
+template<typename T>
+ASStreamIterator<T>::~ASStreamIterator()
+{
+}
+
+/**
+* get the length of the input stream.
+* streamLength variable is set by the constructor.
+*
+* @return length of the input file stream, converted to an int.
+*/
+template<typename T>
+int ASStreamIterator<T>::getStreamLength() const
+{
+ return static_cast<int>(streamLength);
+}
+
+/**
+ * read the input stream, delete any end of line characters,
+ * and build a string that contains the input line.
+ *
+ * @return string containing the next input line minus any end of line characters
+ */
+template<typename T>
+string ASStreamIterator<T>::nextLine(bool emptyLineWasDeleted)
+{
+ // verify that the current position is correct
+ assert(peekStart == 0);
+
+ // a deleted line may be replaced if break-blocks is requested
+ // this sets up the compare to check for a replaced empty line
+ if (prevLineDeleted)
+ {
+ prevLineDeleted = false;
+ checkForEmptyLine = true;
+ }
+ if (!emptyLineWasDeleted)
+ prevBuffer = buffer;
+ else
+ prevLineDeleted = true;
+
+ // read the next record
+ buffer.clear();
+ char ch;
+ inStream->get(ch);
+
+ while (!inStream->eof() && ch != '\n' && ch != '\r')
+ {
+ buffer.append(1, ch);
+ inStream->get(ch);
+ }
+
+ if (inStream->eof())
+ {
+ return buffer;
+ }
+
+ int peekCh = inStream->peek();
+
+ // find input end-of-line characters
+ if (!inStream->eof())
+ {
+ if (ch == '\r') // CR+LF is windows otherwise Mac OS 9
+ {
+ if (peekCh == '\n')
+ {
+ inStream->get();
+ eolWindows++;
+ }
+ else
+ eolMacOld++;
+ }
+ else // LF is Linux, allow for improbable LF/CR
+ {
+ if (peekCh == '\r')
+ {
+ inStream->get();
+ eolWindows++;
+ }
+ else
+ eolLinux++;
+ }
+ }
+ else
+ {
+ inStream->clear();
+ }
+
+ // set output end of line characters
+ if (eolWindows >= eolLinux)
+ {
+ if (eolWindows >= eolMacOld)
+ outputEOL = "\r\n"; // Windows (CR+LF)
+ else
+ outputEOL = "\r"; // MacOld (CR)
+ }
+ else if (eolLinux >= eolMacOld)
+ outputEOL = "\n"; // Linux (LF)
+ else
+ outputEOL = "\r"; // MacOld (CR)
+
+ return buffer;
+}
+
+// save the current position and get the next line
+// this can be called for multiple reads
+// when finished peeking you MUST call peekReset()
+// call this function from ASFormatter ONLY
+template<typename T>
+string ASStreamIterator<T>::peekNextLine()
+{
+ assert(hasMoreLines());
+ string nextLine_;
+ char ch;
+
+ if (peekStart == 0)
+ peekStart = inStream->tellg();
+
+ // read the next record
+ inStream->get(ch);
+ while (!inStream->eof() && ch != '\n' && ch != '\r')
+ {
+ nextLine_.append(1, ch);
+ inStream->get(ch);
+ }
+
+ if (inStream->eof())
+ {
+ return nextLine_;
+ }
+
+ int peekCh = inStream->peek();
+
+ // remove end-of-line characters
+ if (!inStream->eof())
+ {
+ if ((peekCh == '\n' || peekCh == '\r') && peekCh != ch)
+ inStream->get();
+ }
+
+ return nextLine_;
+}
+
+// reset current position and EOF for peekNextLine()
+template<typename T>
+void ASStreamIterator<T>::peekReset()
+{
+ assert(peekStart != 0);
+ inStream->clear();
+ inStream->seekg(peekStart);
+ peekStart = 0;
+}
+
+// save the last input line after input has reached EOF
+template<typename T>
+void ASStreamIterator<T>::saveLastInputLine()
+{
+ assert(inStream->eof());
+ prevBuffer = buffer;
+}
+
+// return position of the get pointer
+template<typename T>
+streamoff ASStreamIterator<T>::tellg()
+{
+ return inStream->tellg();
+}
+
+// check for a change in line ends
+template<typename T>
+bool ASStreamIterator<T>::getLineEndChange(int lineEndFormat) const
+{
+ assert(lineEndFormat == LINEEND_DEFAULT
+ || lineEndFormat == LINEEND_WINDOWS
+ || lineEndFormat == LINEEND_LINUX
+ || lineEndFormat == LINEEND_MACOLD);
+
+ bool lineEndChange = false;
+ if (lineEndFormat == LINEEND_WINDOWS)
+ lineEndChange = (eolLinux + eolMacOld != 0);
+ else if (lineEndFormat == LINEEND_LINUX)
+ lineEndChange = (eolWindows + eolMacOld != 0);
+ else if (lineEndFormat == LINEEND_MACOLD)
+ lineEndChange = (eolWindows + eolLinux != 0);
+ else
+ {
+ if (eolWindows > 0)
+ lineEndChange = (eolLinux + eolMacOld != 0);
+ else if (eolLinux > 0)
+ lineEndChange = (eolWindows + eolMacOld != 0);
+ else if (eolMacOld > 0)
+ lineEndChange = (eolWindows + eolLinux != 0);
+ }
+ return lineEndChange;
+}
+
+//-----------------------------------------------------------------------------
+// ASConsole class
+// main function will be included only in the console build
+//-----------------------------------------------------------------------------
+
+#ifndef ASTYLE_LIB
+
+ASConsole::ASConsole(ASFormatter& formatterArg) : formatter(formatterArg)
+{
+ errorStream = &cerr;
+ // command line options
+ isRecursive = false;
+ isDryRun = false;
+ noBackup = false;
+ preserveDate = false;
+ isVerbose = false;
+ isQuiet = false;
+ isFormattedOnly = false;
+ ignoreExcludeErrors = false;
+ ignoreExcludeErrorsDisplay = false;
+ optionsFileRequired = false;
+ useAscii = false;
+ // other variables
+ bypassBrowserOpen = false;
+ hasWildcard = false;
+ filesAreIdentical = true;
+ lineEndsMixed = false;
+ origSuffix = ".orig";
+ mainDirectoryLength = 0;
+ filesFormatted = 0;
+ filesUnchanged = 0;
+ linesOut = 0;
+}
+
+ASConsole::~ASConsole()
+{}
+
+// rewrite a stringstream converting the line ends
+void ASConsole::convertLineEnds(ostringstream& out, int lineEnd)
+{
+ assert(lineEnd == LINEEND_WINDOWS || lineEnd == LINEEND_LINUX || lineEnd == LINEEND_MACOLD);
+ const string& inStr = out.str(); // avoids strange looking syntax
+ string outStr; // the converted output
+ int inLength = (int)inStr.length();
+ for (int pos = 0; pos < inLength; pos++)
+ {
+ if (inStr[pos] == '\r')
+ {
+ if (inStr[pos + 1] == '\n')
+ {
+ // CRLF
+ if (lineEnd == LINEEND_CR)
+ {
+ outStr += inStr[pos]; // Delete the LF
+ pos++;
+ continue;
+ }
+ else if (lineEnd == LINEEND_LF)
+ {
+ outStr += inStr[pos + 1]; // Delete the CR
+ pos++;
+ continue;
+ }
+ else
+ {
+ outStr += inStr[pos]; // Do not change
+ outStr += inStr[pos + 1];
+ pos++;
+ continue;
+ }
+ }
+ else
+ {
+ // CR
+ if (lineEnd == LINEEND_CRLF)
+ {
+ outStr += inStr[pos]; // Insert the CR
+ outStr += '\n'; // Insert the LF
+ continue;
+ }
+ else if (lineEnd == LINEEND_LF)
+ {
+ outStr += '\n'; // Insert the LF
+ continue;
+ }
+ else
+ {
+ outStr += inStr[pos]; // Do not change
+ continue;
+ }
+ }
+ }
+ else if (inStr[pos] == '\n')
+ {
+ // LF
+ if (lineEnd == LINEEND_CRLF)
+ {
+ outStr += '\r'; // Insert the CR
+ outStr += inStr[pos]; // Insert the LF
+ continue;
+ }
+ else if (lineEnd == LINEEND_CR)
+ {
+ outStr += '\r'; // Insert the CR
+ continue;
+ }
+ else
+ {
+ outStr += inStr[pos]; // Do not change
+ continue;
+ }
+ }
+ else
+ {
+ outStr += inStr[pos]; // Write the current char
+ }
+ }
+ // replace the stream
+ out.str(outStr);
+}
+
+void ASConsole::correctMixedLineEnds(ostringstream& out)
+{
+ LineEndFormat lineEndFormat = LINEEND_DEFAULT;
+ if (outputEOL == "\r\n")
+ lineEndFormat = LINEEND_WINDOWS;
+ if (outputEOL == "\n")
+ lineEndFormat = LINEEND_LINUX;
+ if (outputEOL == "\r")
+ lineEndFormat = LINEEND_MACOLD;
+ convertLineEnds(out, lineEndFormat);
+}
+
+// check files for 16 or 32 bit encoding
+// the file must have a Byte Order Mark (BOM)
+// NOTE: some string functions don't work with NULLs (e.g. length())
+FileEncoding ASConsole::detectEncoding(const char* data, size_t dataSize) const
+{
+ FileEncoding encoding = ENCODING_8BIT;
+
+ if (dataSize >= 4 && memcmp(data, "\x00\x00\xFE\xFF", 4) == 0)
+ encoding = UTF_32BE;
+ else if (dataSize >= 4 && memcmp(data, "\xFF\xFE\x00\x00", 4) == 0)
+ encoding = UTF_32LE;
+ else if (dataSize >= 2 && memcmp(data, "\xFE\xFF", 2) == 0)
+ encoding = UTF_16BE;
+ else if (dataSize >= 2 && memcmp(data, "\xFF\xFE", 2) == 0)
+ encoding = UTF_16LE;
+
+ return encoding;
+}
+
+// error exit without a message
+void ASConsole::error() const
+{
+ (*errorStream) << _("\nArtistic Style has terminated") << endl;
+ exit(EXIT_FAILURE);
+}
+
+// error exit with a message
+void ASConsole::error(const char* why, const char* what) const
+{
+ (*errorStream) << why << ' ' << what << endl;
+ error();
+}
+
+/**
+ * If no files have been given, use cin for input and cout for output.
+ *
+ * This is used to format text for text editors like TextWrangler (Mac).
+ * Do NOT display any console messages when this function is used.
+ */
+void ASConsole::formatCinToCout()
+{
+ // check for files from --stdin= and --stdout=
+ if (!stdPathIn.empty())
+ {
+ if (!freopen(stdPathIn.c_str(), "r", stdin))
+ error("Cannot open input file", stdPathIn.c_str());
+ }
+ if (!stdPathOut.empty())
+ {
+ if (!freopen(stdPathOut.c_str(), "w", stdout))
+ error("Cannot open output file", stdPathOut.c_str());
+
+ }
+ // Using cin.tellg() causes problems with both Windows and Linux.
+ // The Windows problem occurs when the input is not Windows line-ends.
+ // The tellg() will be out of sequence with the get() statements.
+ // The Linux cin.tellg() will return -1 (invalid).
+ // Copying the input sequentially to a stringstream before
+ // formatting solves the problem for both.
+ istream* inStream = &cin;
+ stringstream outStream;
+ char ch;
+ inStream->get(ch);
+ while (!inStream->eof() && !inStream->fail())
+ {
+ outStream.put(ch);
+ inStream->get(ch);
+ }
+ ASStreamIterator<stringstream> streamIterator(&outStream);
+ // Windows pipe or redirection always outputs Windows line-ends.
+ // Linux pipe or redirection will output any line end.
+#ifdef _WIN32
+ LineEndFormat lineEndFormat = LINEEND_DEFAULT;
+#else
+ LineEndFormat lineEndFormat = formatter.getLineEndFormat();
+#endif // _WIN32
+ initializeOutputEOL(lineEndFormat);
+ formatter.init(&streamIterator);
+
+ while (formatter.hasMoreLines())
+ {
+ cout << formatter.nextLine();
+ if (formatter.hasMoreLines())
+ {
+ setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
+ cout << outputEOL;
+ }
+ else
+ {
+ // this can happen if the file if missing a closing brace and break-blocks is requested
+ if (formatter.getIsLineReady())
+ {
+ setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
+ cout << outputEOL;
+ cout << formatter.nextLine();
+ }
+ }
+ }
+ cout.flush();
+}
+
+/**
+ * Open input file, format it, and close the output.
+ *
+ * @param fileName_ The path and name of the file to be processed.
+ */
+void ASConsole::formatFile(const string& fileName_)
+{
+ stringstream in;
+ ostringstream out;
+ FileEncoding encoding = readFile(fileName_, in);
+
+ // Unless a specific language mode has been set, set the language mode
+ // according to the file's suffix.
+ if (!formatter.getModeManuallySet())
+ {
+ if (stringEndsWith(fileName_, string(".java")))
+ formatter.setJavaStyle();
+ else if (stringEndsWith(fileName_, string(".cs")))
+ formatter.setSharpStyle();
+ else
+ formatter.setCStyle();
+ }
+
+ // set line end format
+ string nextLine; // next output line
+ filesAreIdentical = true; // input and output files are identical
+ LineEndFormat lineEndFormat = formatter.getLineEndFormat();
+ initializeOutputEOL(lineEndFormat);
+ // do this AFTER setting the file mode
+ ASStreamIterator<stringstream> streamIterator(&in);
+ formatter.init(&streamIterator);
+
+ // format the file
+ while (formatter.hasMoreLines())
+ {
+ nextLine = formatter.nextLine();
+ out << nextLine;
+ linesOut++;
+ if (formatter.hasMoreLines())
+ {
+ setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
+ out << outputEOL;
+ }
+ else
+ {
+ streamIterator.saveLastInputLine(); // to compare the last input line
+ // this can happen if the file if missing a closing brace and break-blocks is requested
+ if (formatter.getIsLineReady())
+ {
+ setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
+ out << outputEOL;
+ nextLine = formatter.nextLine();
+ out << nextLine;
+ linesOut++;
+ streamIterator.saveLastInputLine();
+ }
+ }
+
+ if (filesAreIdentical)
+ {
+ if (streamIterator.checkForEmptyLine)
+ {
+ if (nextLine.find_first_not_of(" \t") != string::npos)
+ filesAreIdentical = false;
+ }
+ else if (!streamIterator.compareToInputBuffer(nextLine))
+ filesAreIdentical = false;
+ streamIterator.checkForEmptyLine = false;
+ }
+ }
+ // correct for mixed line ends
+ if (lineEndsMixed)
+ {
+ correctMixedLineEnds(out);
+ filesAreIdentical = false;
+ }
+
+ // remove targetDirectory from filename if required by print
+ string displayName;
+ if (hasWildcard)
+ displayName = fileName_.substr(targetDirectory.length() + 1);
+ else
+ displayName = fileName_;
+
+ // if file has changed, write the new file
+ if (!filesAreIdentical || streamIterator.getLineEndChange(lineEndFormat))
+ {
+ if (!isDryRun)
+ writeFile(fileName_, encoding, out);
+ printMsg(_("Formatted %s\n"), displayName);
+ filesFormatted++;
+ }
+ else
+ {
+ if (!isFormattedOnly)
+ printMsg(_("Unchanged %s\n"), displayName);
+ filesUnchanged++;
+ }
+
+ assert(formatter.getChecksumDiff() == 0);
+}
+
+// build a vector of argv options
+// the program path argv[0] is excluded
+vector<string> ASConsole::getArgvOptions(int argc, char** argv) const
+{
+ vector<string> argvOptions;
+ for (int i = 1; i < argc; i++)
+ {
+ argvOptions.emplace_back(string(argv[i]));
+ }
+ return argvOptions;
+}
+
+// for unit testing
+vector<bool> ASConsole::getExcludeHitsVector() const
+{ return excludeHitsVector; }
+
+// for unit testing
+vector<string> ASConsole::getExcludeVector() const
+{ return excludeVector; }
+
+// for unit testing
+vector<string> ASConsole::getFileName() const
+{ return fileName; }
+
+// for unit testing
+vector<string> ASConsole::getFileNameVector() const
+{ return fileNameVector; }
+
+// for unit testing
+vector<string> ASConsole::getFileOptionsVector() const
+{ return fileOptionsVector; }
+
+// for unit testing
+bool ASConsole::getFilesAreIdentical() const
+{ return filesAreIdentical; }
+
+// for unit testing
+int ASConsole::getFilesFormatted() const
+{ return filesFormatted; }
+
+// for unit testing
+bool ASConsole::getIgnoreExcludeErrors() const
+{ return ignoreExcludeErrors; }
+
+// for unit testing
+bool ASConsole::getIgnoreExcludeErrorsDisplay() const
+{ return ignoreExcludeErrorsDisplay; }
+
+// for unit testing
+bool ASConsole::getIsDryRun() const
+{ return isDryRun; }
+
+// for unit testing
+bool ASConsole::getIsFormattedOnly() const
+{ return isFormattedOnly; }
+
+// for unit testing
+string ASConsole::getLanguageID() const
+{ return localizer.getLanguageID(); }
+
+// for unit testing
+bool ASConsole::getIsQuiet() const
+{ return isQuiet; }
+
+// for unit testing
+bool ASConsole::getIsRecursive() const
+{ return isRecursive; }
+
+// for unit testing
+bool ASConsole::getIsVerbose() const
+{ return isVerbose; }
+
+// for unit testing
+bool ASConsole::getLineEndsMixed() const
+{ return lineEndsMixed; }
+
+// for unit testing
+bool ASConsole::getNoBackup() const
+{ return noBackup; }
+
+// for unit testing
+string ASConsole::getOptionsFileName() const
+{ return optionsFileName; }
+
+// for unit testing
+vector<string> ASConsole::getOptionsVector() const
+{ return optionsVector; }
+
+// for unit testing
+string ASConsole::getOrigSuffix() const
+{ return origSuffix; }
+
+// for unit testing
+bool ASConsole::getPreserveDate() const
+{ return preserveDate; }
+
+// for unit testing
+string ASConsole::getStdPathIn() const
+{ return stdPathIn; }
+
+// for unit testing
+string ASConsole::getStdPathOut() const
+{ return stdPathOut; }
+
+// for unit testing
+void ASConsole::setBypassBrowserOpen(bool state)
+{ bypassBrowserOpen = state; }
+
+// for unit testing
+ostream* ASConsole::getErrorStream() const
+{
+ return errorStream;
+}
+
+void ASConsole::setErrorStream(ostream* errStreamPtr)
+{
+ errorStream = errStreamPtr;
+}
+
+string ASConsole::getParam(const string& arg, const char* op)
+{
+ return arg.substr(strlen(op));
+}
+
+// initialize output end of line
+void ASConsole::initializeOutputEOL(LineEndFormat lineEndFormat)
+{
+ assert(lineEndFormat == LINEEND_DEFAULT
+ || lineEndFormat == LINEEND_WINDOWS
+ || lineEndFormat == LINEEND_LINUX
+ || lineEndFormat == LINEEND_MACOLD);
+
+ outputEOL.clear(); // current line end
+ prevEOL.clear(); // previous line end
+ lineEndsMixed = false; // output has mixed line ends, LINEEND_DEFAULT only
+
+ if (lineEndFormat == LINEEND_WINDOWS)
+ outputEOL = "\r\n";
+ else if (lineEndFormat == LINEEND_LINUX)
+ outputEOL = "\n";
+ else if (lineEndFormat == LINEEND_MACOLD)
+ outputEOL = "\r";
+ else
+ outputEOL.clear();
+}
+
+FileEncoding ASConsole::readFile(const string& fileName_, stringstream& in) const
+{
+ const int blockSize = 65536; // 64 KB
+ ifstream fin(fileName_.c_str(), ios::binary);
+ if (!fin)
+ error("Cannot open input file", fileName_.c_str());
+ char* data = new (nothrow) char[blockSize];
+ if (data == nullptr)
+ error("Cannot allocate memory for input file", fileName_.c_str());
+ fin.read(data, blockSize);
+ if (fin.bad())
+ error("Cannot read input file", fileName_.c_str());
+ size_t dataSize = static_cast<size_t>(fin.gcount());
+ FileEncoding encoding = detectEncoding(data, dataSize);
+ if (encoding == UTF_32BE || encoding == UTF_32LE)
+ error(_("Cannot process UTF-32 encoding"), fileName_.c_str());
+ bool firstBlock = true;
+ bool isBigEndian = (encoding == UTF_16BE);
+ while (dataSize != 0)
+ {
+ if (encoding == UTF_16LE || encoding == UTF_16BE)
+ {
+ // convert utf-16 to utf-8
+ size_t utf8Size = utf8_16.utf8LengthFromUtf16(data, dataSize, isBigEndian);
+ char* utf8Out = new (nothrow) char[utf8Size];
+ if (utf8Out == nullptr)
+ error("Cannot allocate memory for utf-8 conversion", fileName_.c_str());
+ size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize, isBigEndian, firstBlock, utf8Out);
+ assert(utf8Len == utf8Size);
+ in << string(utf8Out, utf8Len);
+ delete[] utf8Out;
+ }
+ else
+ in << string(data, dataSize);
+ fin.read(data, blockSize);
+ if (fin.bad())
+ error("Cannot read input file", fileName_.c_str());
+ dataSize = static_cast<size_t>(fin.gcount());
+ firstBlock = false;
+ }
+ fin.close();
+ delete[] data;
+ return encoding;
+}
+
+void ASConsole::setIgnoreExcludeErrors(bool state)
+{ ignoreExcludeErrors = state; }
+
+void ASConsole::setIgnoreExcludeErrorsAndDisplay(bool state)
+{ ignoreExcludeErrors = state; ignoreExcludeErrorsDisplay = state; }
+
+void ASConsole::setIsFormattedOnly(bool state)
+{ isFormattedOnly = state; }
+
+void ASConsole::setIsQuiet(bool state)
+{ isQuiet = state; }
+
+void ASConsole::setIsRecursive(bool state)
+{ isRecursive = state; }
+
+void ASConsole::setIsDryRun(bool state)
+{ isDryRun = state; }
+
+void ASConsole::setIsVerbose(bool state)
+{ isVerbose = state; }
+
+void ASConsole::setNoBackup(bool state)
+{ noBackup = state; }
+
+void ASConsole::setOptionsFileName(const string& name)
+{ optionsFileName = name; }
+
+void ASConsole::setOrigSuffix(const string& suffix)
+{ origSuffix = suffix; }
+
+void ASConsole::setPreserveDate(bool state)
+{ preserveDate = state; }
+
+void ASConsole::setStdPathIn(const string& path)
+{ stdPathIn = path; }
+
+void ASConsole::setStdPathOut(const string& path)
+{ stdPathOut = path; }
+
+// set outputEOL variable
+void ASConsole::setOutputEOL(LineEndFormat lineEndFormat, const string& currentEOL)
+{
+ if (lineEndFormat == LINEEND_DEFAULT)
+ {
+ outputEOL = currentEOL;
+ if (prevEOL.empty())
+ prevEOL = outputEOL;
+ if (prevEOL != outputEOL)
+ {
+ lineEndsMixed = true;
+ filesAreIdentical = false;
+ prevEOL = outputEOL;
+ }
+ }
+ else
+ {
+ prevEOL = currentEOL;
+ if (prevEOL != outputEOL)
+ filesAreIdentical = false;
+ }
+}
+
+#ifdef _WIN32 // Windows specific
+
+/**
+ * WINDOWS function to display the last system error.
+ */
+void ASConsole::displayLastError()
+{
+ LPSTR msgBuf;
+ DWORD lastError = GetLastError();
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ nullptr,
+ lastError,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPSTR) &msgBuf,
+ 0,
+ nullptr
+ );
+ // Display the string.
+ (*errorStream) << "Error (" << lastError << ") " << msgBuf << endl;
+ // Free the buffer.
+ LocalFree(msgBuf);
+}
+
+/**
+ * WINDOWS function to get the current directory.
+ * NOTE: getenv("CD") does not work for Windows Vista.
+ * The Windows function GetCurrentDirectory is used instead.
+ *
+ * @return The path of the current directory
+ */
+string ASConsole::getCurrentDirectory(const string& fileName_) const
+{
+ char currdir[MAX_PATH];
+ currdir[0] = '\0';
+ if (!GetCurrentDirectory(sizeof(currdir), currdir))
+ error("Cannot find file", fileName_.c_str());
+ return string(currdir);
+}
+
+/**
+ * WINDOWS function to resolve wildcards and recurse into sub directories.
+ * The fileName vector is filled with the path and names of files to process.
+ *
+ * @param directory The path of the directory to be processed.
+ * @param wildcard The wildcard to be processed (e.g. *.cpp).
+ */
+void ASConsole::getFileNames(const string& directory, const string& wildcard)
+{
+ vector<string> subDirectory; // sub directories of directory
+ WIN32_FIND_DATA findFileData; // for FindFirstFile and FindNextFile
+
+ // Find the first file in the directory
+ // Find will get at least "." and "..".
+ string firstFile = directory + "\\*";
+ HANDLE hFind = FindFirstFile(firstFile.c_str(), &findFileData);
+
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ // Error (3) The system cannot find the path specified.
+ // Error (123) The filename, directory name, or volume label syntax is incorrect.
+ // ::FindClose(hFind); before exiting
+ displayLastError();
+ error(_("Cannot open directory"), directory.c_str());
+ }
+
+ // save files and sub directories
+ do
+ {
+ // skip hidden or read only
+ if (findFileData.cFileName[0] == '.'
+ || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
+ || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
+ continue;
+
+ // is this a sub directory
+ if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ if (!isRecursive)
+ continue;
+ // if a sub directory and recursive, save sub directory
+ string subDirectoryPath = directory + g_fileSeparator + findFileData.cFileName;
+ if (isPathExclued(subDirectoryPath))
+ printMsg(_("Exclude %s\n"), subDirectoryPath.substr(mainDirectoryLength));
+ else
+ subDirectory.emplace_back(subDirectoryPath);
+ continue;
+ }
+
+ // save the file name
+ string filePathName = directory + g_fileSeparator + findFileData.cFileName;
+ // check exclude before wildcmp to avoid "unmatched exclude" error
+ bool isExcluded = isPathExclued(filePathName);
+ // save file name if wildcard match
+ if (wildcmp(wildcard.c_str(), findFileData.cFileName))
+ {
+ if (isExcluded)
+ printMsg(_("Exclude %s\n"), filePathName.substr(mainDirectoryLength));
+ else
+ fileName.emplace_back(filePathName);
+ }
+ }
+ while (FindNextFile(hFind, &findFileData) != 0);
+
+ // check for processing error
+ ::FindClose(hFind);
+ DWORD dwError = GetLastError();
+ if (dwError != ERROR_NO_MORE_FILES)
+ error("Error processing directory", directory.c_str());
+
+ // recurse into sub directories
+ // if not doing recursive subDirectory is empty
+ for (unsigned i = 0; i < subDirectory.size(); i++)
+ getFileNames(subDirectory[i], wildcard);
+
+ return;
+}
+
+/**
+ * WINDOWS function to format a number according to the current locale.
+ * This formats positive integers only, no float.
+ *
+ * @param num The number to be formatted.
+ * @param lcid The LCID of the locale to be used for testing.
+ * @return The formatted number.
+ */
+string ASConsole::getNumberFormat(int num, size_t lcid) const
+{
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
+ // Compilers that don't support C++ locales should still support this assert.
+ // The C locale should be set but not the C++.
+ // This function is not necessary if the C++ locale is set.
+ // The locale().name() return value is not portable to all compilers.
+ assert(locale().name() == "C");
+#endif
+ // convert num to a string
+ stringstream alphaNum;
+ alphaNum << num;
+ string number = alphaNum.str();
+ if (useAscii)
+ return number;
+
+ // format the number using the Windows API
+ if (lcid == 0)
+ lcid = LOCALE_USER_DEFAULT;
+ int outSize = ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, nullptr, 0);
+ char* outBuf = new (nothrow) char[outSize];
+ if (outBuf == nullptr)
+ return number;
+ ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, outBuf, outSize);
+ string formattedNum(outBuf);
+ delete[] outBuf;
+ // remove the decimal
+ int decSize = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, nullptr, 0);
+ char* decBuf = new (nothrow) char[decSize];
+ if (decBuf == nullptr)
+ return number;
+ ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, decBuf, decSize);
+ size_t i = formattedNum.rfind(decBuf);
+ delete[] decBuf;
+ if (i != string::npos)
+ formattedNum.erase(i);
+ if (!formattedNum.length())
+ formattedNum = "0";
+ return formattedNum;
+}
+
+/**
+ * WINDOWS function to open a HTML file in the default browser.
+ */
+void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
+{
+ struct stat statbuf;
+ const char* envPaths[] = { "PROGRAMFILES(X86)", "PROGRAMFILES" };
+ size_t pathsLen = sizeof(envPaths) / sizeof(envPaths[0]);
+ string htmlDefaultPath;
+ for (size_t i = 0; i < pathsLen; i++)
+ {
+ const char* envPath = getenv(envPaths[i]);
+ if (envPath == nullptr)
+ continue;
+ htmlDefaultPath = envPath;
+ if (htmlDefaultPath.length() > 0
+ && htmlDefaultPath[htmlDefaultPath.length() - 1] == g_fileSeparator)
+ htmlDefaultPath.erase(htmlDefaultPath.length() - 1);
+ htmlDefaultPath.append("\\AStyle\\doc");
+ if (stat(htmlDefaultPath.c_str(), &statbuf) == 0 && statbuf.st_mode & S_IFDIR)
+ break;
+ }
+ htmlDefaultPath.append("\\");
+
+ // build file path
+ string htmlFilePath;
+ if (filePathIn == nullptr)
+ htmlFilePath = htmlDefaultPath + "astyle.html";
+ else
+ {
+ if (strpbrk(filePathIn, "\\/") == nullptr)
+ htmlFilePath = htmlDefaultPath + filePathIn;
+ else
+ htmlFilePath = filePathIn;
+ }
+ standardizePath(htmlFilePath);
+ if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
+ {
+ printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
+ return;
+ }
+
+ SHELLEXECUTEINFO sei = { sizeof(sei), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ sei.fMask = SEE_MASK_FLAG_NO_UI;
+ sei.lpVerb = "open";
+ sei.lpFile = htmlFilePath.c_str();
+ sei.nShow = SW_SHOWNORMAL;
+
+ // browser open will be bypassed in test programs
+ printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
+ if (!bypassBrowserOpen)
+ {
+ int ret = ShellExecuteEx(&sei);
+ if (!ret)
+ error(_("Command execute failure"), htmlFilePath.c_str());
+ }
+}
+
+#else // Linux specific
+
+/**
+ * LINUX function to get the current directory.
+ * This is done if the fileName does not contain a path.
+ * It is probably from an editor sending a single file.
+ *
+ * @param fileName_ The filename is used only for the error message.
+ * @return The path of the current directory
+ */
+string ASConsole::getCurrentDirectory(const string& fileName_) const
+{
+ char* currdir = getenv("PWD");
+ if (currdir == nullptr)
+ error("Cannot find file", fileName_.c_str());
+ return string(currdir);
+}
+
+/**
+ * LINUX function to resolve wildcards and recurse into sub directories.
+ * The fileName vector is filled with the path and names of files to process.
+ *
+ * @param directory The path of the directory to be processed.
+ * @param wildcard The wildcard to be processed (e.g. *.cpp).
+ */
+void ASConsole::getFileNames(const string& directory, const string& wildcard)
+{
+ struct dirent* entry; // entry from readdir()
+ struct stat statbuf; // entry from stat()
+ vector<string> subDirectory; // sub directories of this directory
+
+ // errno is defined in <errno.h> and is set for errors in opendir, readdir, or stat
+ errno = 0;
+
+ DIR* dp = opendir(directory.c_str());
+ if (dp == nullptr)
+ error(_("Cannot open directory"), directory.c_str());
+
+ // save the first fileName entry for this recursion
+ const unsigned firstEntry = fileName.size();
+
+ // save files and sub directories
+ while ((entry = readdir(dp)) != nullptr)
+ {
+ // get file status
+ string entryFilepath = directory + g_fileSeparator + entry->d_name;
+ if (stat(entryFilepath.c_str(), &statbuf) != 0)
+ {
+ if (errno == EOVERFLOW) // file over 2 GB is OK
+ {
+ errno = 0;
+ continue;
+ }
+ perror("errno message");
+ error("Error getting file status in directory", directory.c_str());
+ }
+ // skip hidden or read only
+ if (entry->d_name[0] == '.' || !(statbuf.st_mode & S_IWUSR))
+ continue;
+ // if a sub directory and recursive, save sub directory
+ if (S_ISDIR(statbuf.st_mode) && isRecursive)
+ {
+ if (isPathExclued(entryFilepath))
+ printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
+ else
+ subDirectory.emplace_back(entryFilepath);
+ continue;
+ }
+
+ // if a file, save file name
+ if (S_ISREG(statbuf.st_mode))
+ {
+ // check exclude before wildcmp to avoid "unmatched exclude" error
+ bool isExcluded = isPathExclued(entryFilepath);
+ // save file name if wildcard match
+ if (wildcmp(wildcard.c_str(), entry->d_name) != 0)
+ {
+ if (isExcluded)
+ printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
+ else
+ fileName.emplace_back(entryFilepath);
+ }
+ }
+ }
+
+ if (closedir(dp) != 0)
+ {
+ perror("errno message");
+ error("Error reading directory", directory.c_str());
+ }
+
+ // sort the current entries for fileName
+ if (firstEntry < fileName.size())
+ sort(&fileName[firstEntry], &fileName[fileName.size()]);
+
+ // recurse into sub directories
+ // if not doing recursive, subDirectory is empty
+ if (subDirectory.size() > 1)
+ sort(subDirectory.begin(), subDirectory.end());
+ for (unsigned i = 0; i < subDirectory.size(); i++)
+ {
+ getFileNames(subDirectory[i], wildcard);
+ }
+}
+
+/**
+ * LINUX function to get locale information and call getNumberFormat.
+ * This formats positive integers only, no float.
+ *
+ * @param num The number to be formatted.
+ * size_t is for compatibility with the Windows function.
+ * @return The formatted number.
+ */
+string ASConsole::getNumberFormat(int num, size_t /*lcid*/) const
+{
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
+ // Compilers that don't support C++ locales should still support this assert.
+ // The C locale should be set but not the C++.
+ // This function is not necessary if the C++ locale is set.
+ // The locale().name() return value is not portable to all compilers.
+ assert(locale().name() == "C");
+#endif
+
+ // get the locale info
+ struct lconv* lc;
+ lc = localeconv();
+
+ // format the number
+ return getNumberFormat(num, lc->grouping, lc->thousands_sep);
+}
+
+/**
+ * LINUX function to format a number according to the current locale.
+ * This formats positive integers only, no float.
+ *
+ * @param num The number to be formatted.
+ * @param groupingArg The grouping string from the locale.
+ * @param separator The thousands group separator from the locale.
+ * @return The formatted number.
+ */
+string ASConsole::getNumberFormat(int num, const char* groupingArg, const char* separator) const
+{
+ // convert num to a string
+ stringstream alphaNum;
+ alphaNum << num;
+ string number = alphaNum.str();
+ // format the number from right to left
+ string formattedNum;
+ size_t ig = 0; // grouping index
+ int grouping = groupingArg[ig];
+ int i = number.length();
+ // check for no grouping
+ if (grouping == 0)
+ grouping = number.length();
+ while (i > 0)
+ {
+ // extract a group of numbers
+ string group;
+ if (i < grouping)
+ group = number;
+ else
+ group = number.substr(i - grouping);
+ // update formatted number
+ formattedNum.insert(0, group);
+ i -= grouping;
+ if (i < 0)
+ i = 0;
+ if (i > 0)
+ formattedNum.insert(0, separator);
+ number.erase(i);
+ // update grouping
+ if (groupingArg[ig] != '\0'
+ && groupingArg[ig + 1] != '\0')
+ grouping = groupingArg[++ig];
+ }
+ return formattedNum;
+}
+
+/**
+ * LINUX function to open a HTML file in the default browser.
+ * Use xdg-open from freedesktop.org cross-desktop compatibility suite xdg-utils.
+ * see http://portland.freedesktop.org/wiki/
+ * This is installed on most modern distributions.
+ */
+void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
+{
+ struct stat statbuf;
+ string htmlDefaultPath = "/usr/share/doc/astyle/html/";
+ string htmlDefaultFile = "astyle.html";
+
+ // build file path
+ string htmlFilePath;
+ if (filePathIn == nullptr)
+ htmlFilePath = htmlDefaultPath + htmlDefaultFile;
+ else
+ {
+ if (strpbrk(filePathIn, "\\/") == nullptr)
+ htmlFilePath = htmlDefaultPath + filePathIn;
+ else
+ htmlFilePath = filePathIn;
+ }
+ standardizePath(htmlFilePath);
+ if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
+ {
+ printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
+ return;
+ }
+
+ // get search paths
+ const char* envPaths = getenv("PATH");
+ if (envPaths == nullptr)
+ envPaths = "?";
+ size_t envlen = strlen(envPaths);
+ char* paths = new char[envlen + 1];
+ strcpy(paths, envPaths);
+ // find xdg-open (usually in /usr/bin)
+ // Mac uses open instead
+#ifdef __APPLE__
+ const char* fileOpen = "open";
+#else
+ const char* fileOpen = "xdg-open";
+#endif
+ string searchPath;
+ char* searchDir = strtok(paths, ":");
+ while (searchDir != nullptr)
+ {
+ searchPath = searchDir;
+ if (searchPath.length() > 0
+ && searchPath[searchPath.length() - 1] != g_fileSeparator)
+ searchPath.append(string(1, g_fileSeparator));
+ searchPath.append(fileOpen);
+ if (stat(searchPath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
+ break;
+ searchDir = strtok(nullptr, ":");
+ }
+ delete[] paths;
+ if (searchDir == nullptr)
+ error(_("Command is not installed"), fileOpen);
+
+ // browser open will be bypassed in test programs
+ printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
+ if (!bypassBrowserOpen)
+ {
+ execlp(fileOpen, fileOpen, htmlFilePath.c_str(), nullptr);
+ // execlp will NOT return if successful
+ error(_("Command execute failure"), fileOpen);
+ }
+}
+
+#endif // _WIN32
+
+// get individual file names from the command-line file path
+void ASConsole::getFilePaths(const string& filePath)
+{
+ fileName.clear();
+ targetDirectory = string();
+ targetFilename = string();
+
+ // separate directory and file name
+ size_t separator = filePath.find_last_of(g_fileSeparator);
+ if (separator == string::npos)
+ {
+ // if no directory is present, use the currently active directory
+ targetDirectory = getCurrentDirectory(filePath);
+ targetFilename = filePath;
+ mainDirectoryLength = targetDirectory.length() + 1; // +1 includes trailing separator
+ }
+ else
+ {
+ targetDirectory = filePath.substr(0, separator);
+ targetFilename = filePath.substr(separator + 1);
+ mainDirectoryLength = targetDirectory.length() + 1; // +1 includes trailing separator
+ }
+
+ if (targetFilename.length() == 0)
+ {
+ fprintf(stderr, _("Missing filename in %s\n"), filePath.c_str());
+ error();
+ }
+
+ // check filename for wildcards
+ hasWildcard = false;
+ if (targetFilename.find_first_of("*?") != string::npos)
+ hasWildcard = true;
+
+ // clear exclude hits vector
+ size_t excludeHitsVectorSize = excludeHitsVector.size();
+ for (size_t ix = 0; ix < excludeHitsVectorSize; ix++)
+ excludeHitsVector[ix] = false;
+
+ // If the filename is not quoted on Linux, bash will replace the
+ // wildcard instead of passing it to the program.
+ if (isRecursive && !hasWildcard)
+ {
+ fprintf(stderr, "%s\n", _("Recursive option with no wildcard"));
+#ifndef _WIN32
+ fprintf(stderr, "%s\n", _("Did you intend quote the filename"));
+#endif
+ error();
+ }
+
+ // display directory name for wildcard processing
+ if (hasWildcard)
+ {
+ printSeparatingLine();
+ printMsg(_("Directory %s\n"), targetDirectory + g_fileSeparator + targetFilename);
+ }
+
+ // create a vector of paths and file names to process
+ if (hasWildcard || isRecursive)
+ getFileNames(targetDirectory, targetFilename);
+ else
+ {
+ // verify a single file is not a directory (needed on Linux)
+ string entryFilepath = targetDirectory + g_fileSeparator + targetFilename;
+ struct stat statbuf;
+ if (stat(entryFilepath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
+ fileName.emplace_back(entryFilepath);
+ }
+
+ // check for unprocessed excludes
+ bool excludeErr = false;
+ for (size_t ix = 0; ix < excludeHitsVector.size(); ix++)
+ {
+ if (!excludeHitsVector[ix])
+ {
+ excludeErr = true;
+ if (!ignoreExcludeErrorsDisplay)
+ {
+ if (ignoreExcludeErrors)
+ printMsg(_("Exclude (unmatched) %s\n"), excludeVector[ix]);
+ else
+ fprintf(stderr, _("Exclude (unmatched) %s\n"), excludeVector[ix].c_str());
+ }
+ else
+ {
+ if (!ignoreExcludeErrors)
+ fprintf(stderr, _("Exclude (unmatched) %s\n"), excludeVector[ix].c_str());
+ }
+ }
+ }
+
+ if (excludeErr && !ignoreExcludeErrors)
+ {
+ if (hasWildcard && !isRecursive)
+ fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
+ error();
+ }
+
+ // check if files were found (probably an input error if not)
+ if (fileName.empty())
+ {
+ fprintf(stderr, _("No file to process %s\n"), filePath.c_str());
+ if (hasWildcard && !isRecursive)
+ fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
+ error();
+ }
+
+ if (hasWildcard)
+ printSeparatingLine();
+}
+
+bool ASConsole::fileNameVectorIsEmpty() const
+{
+ return fileNameVector.empty();
+}
+
+bool ASConsole::isOption(const string& arg, const char* op)
+{
+ return arg.compare(op) == 0;
+}
+
+bool ASConsole::isOption(const string& arg, const char* a, const char* b)
+{
+ return (isOption(arg, a) || isOption(arg, b));
+}
+
+bool ASConsole::isParamOption(const string& arg, const char* option)
+{
+ bool retVal = arg.compare(0, strlen(option), option) == 0;
+ // if comparing for short option, 2nd char of arg must be numeric
+ if (retVal && strlen(option) == 1 && arg.length() > 1)
+ if (!isdigit((unsigned char)arg[1]))
+ retVal = false;
+ return retVal;
+}
+
+// compare a path to the exclude vector
+// used for both directories and filenames
+// updates the g_excludeHitsVector
+// return true if a match
+bool ASConsole::isPathExclued(const string& subPath)
+{
+ bool retVal = false;
+
+ // read the exclude vector checking for a match
+ for (size_t i = 0; i < excludeVector.size(); i++)
+ {
+ string exclude = excludeVector[i];
+
+ if (subPath.length() < exclude.length())
+ continue;
+
+ size_t compareStart = subPath.length() - exclude.length();
+ // subPath compare must start with a directory name
+ if (compareStart > 0)
+ {
+ char lastPathChar = subPath[compareStart - 1];
+ if (lastPathChar != g_fileSeparator)
+ continue;
+ }
+
+ string compare = subPath.substr(compareStart);
+ if (!g_isCaseSensitive)
+ {
+ // make it case insensitive for Windows
+ for (size_t j = 0; j < compare.length(); j++)
+ compare[j] = (char)tolower(compare[j]);
+ for (size_t j = 0; j < exclude.length(); j++)
+ exclude[j] = (char)tolower(exclude[j]);
+ }
+ // compare sub directory to exclude data - must check them all
+ if (compare == exclude)
+ {
+ excludeHitsVector[i] = true;
+ retVal = true;
+ break;
+ }
+ }
+ return retVal;
+}
+
+void ASConsole::printHelp() const
+{
+ cout << endl;
+ cout << " Artistic Style " << g_version << endl;
+ cout << " Maintained by: Jim Pattee\n";
+ cout << " Original Author: Tal Davidson\n";
+ cout << endl;
+ cout << "Usage:\n";
+ cout << "------\n";
+ cout << " astyle [OPTIONS] File1 File2 File3 [...]\n";
+ cout << endl;
+ cout << " astyle [OPTIONS] < Original > Beautified\n";
+ cout << endl;
+ cout << " When indenting a specific file, the resulting indented file RETAINS\n";
+ cout << " the original file-name. The original pre-indented file is renamed,\n";
+ cout << " with a suffix of \'.orig\' added to the original filename.\n";
+ cout << endl;
+ cout << " Wildcards (* and ?) may be used in the filename.\n";
+ cout << " A \'recursive\' option can process directories recursively.\n";
+ cout << endl;
+ cout << " By default, astyle is set up to indent with four spaces per indent,\n";
+ cout << " a maximal indentation of 40 spaces inside continuous statements,\n";
+ cout << " a minimum indentation of eight spaces inside conditional statements,\n";
+ cout << " and NO formatting options.\n";
+ cout << endl;
+ cout << "Options:\n";
+ cout << "--------\n";
+ cout << " This program follows the usual GNU command line syntax.\n";
+ cout << " Long options (starting with '--') must be written one at a time.\n";
+ cout << " Short options (starting with '-') may be appended together.\n";
+ cout << " Thus, -bps4 is the same as -b -p -s4.\n";
+ cout << endl;
+ cout << "Options File:\n";
+ cout << "-------------\n";
+ cout << " Artistic Style looks for a default options file in the\n";
+ cout << " following order:\n";
+ cout << " 1. The contents of the ARTISTIC_STYLE_OPTIONS environment\n";
+ cout << " variable if it exists.\n";
+ cout << " 2. The file called .astylerc in the directory pointed to by the\n";
+ cout << " HOME environment variable ( i.e. $HOME/.astylerc ).\n";
+ cout << " 3. The file called astylerc in the directory pointed to by the\n";
+ cout << " USERPROFILE environment variable (i.e. %USERPROFILE%\\astylerc).\n";
+ cout << " If a default options file is found, the options in this file will\n";
+ cout << " be parsed BEFORE the command-line options.\n";
+ cout << " Long options within the default option file may be written without\n";
+ cout << " the preliminary '--'.\n";
+ cout << endl;
+ cout << "Disable Formatting:\n";
+ cout << "-------------------\n";
+ cout << " Disable Block\n";
+ cout << " Blocks of code can be disabled with the comment tags *INDENT-OFF*\n";
+ cout << " and *INDENT-ON*. It must be contained in a one-line comment.\n";
+ cout << endl;
+ cout << " Disable Line\n";
+ cout << " Padding of operators can be disabled on a single line using the\n";
+ cout << " comment tag *NOPAD*. It must be contained in a line-end comment.\n";
+ cout << endl;
+ cout << "Brace Style Options:\n";
+ cout << "--------------------\n";
+ cout << " default brace style\n";
+ cout << " If no brace style is requested, the opening braces will not be\n";
+ cout << " changed and closing braces will be broken from the preceding line.\n";
+ cout << endl;
+ cout << " --style=allman OR --style=bsd OR --style=break OR -A1\n";
+ cout << " Allman style formatting/indenting.\n";
+ cout << " Broken braces.\n";
+ cout << endl;
+ cout << " --style=java OR --style=attach OR -A2\n";
+ cout << " Java style formatting/indenting.\n";
+ cout << " Attached braces.\n";
+ cout << endl;
+ cout << " --style=kr OR --style=k&r OR --style=k/r OR -A3\n";
+ cout << " Kernighan & Ritchie style formatting/indenting.\n";
+ cout << " Linux braces.\n";
+ cout << endl;
+ cout << " --style=stroustrup OR -A4\n";
+ cout << " Stroustrup style formatting/indenting.\n";
+ cout << " Linux braces.\n";
+ cout << endl;
+ cout << " --style=whitesmith OR -A5\n";
+ cout << " Whitesmith style formatting/indenting.\n";
+ cout << " Broken, indented braces.\n";
+ cout << " Indented class blocks and switch blocks.\n";
+ cout << endl;
+ cout << " --style=vtk OR -A15\n";
+ cout << " VTK style formatting/indenting.\n";
+ cout << " Broken, indented braces except for the opening braces.\n";
+ cout << endl;
+ cout << " --style=banner OR -A6\n";
+ cout << " Banner style formatting/indenting.\n";
+ cout << " Attached, indented braces.\n";
+ cout << endl;
+ cout << " --style=gnu OR -A7\n";
+ cout << " GNU style formatting/indenting.\n";
+ cout << " Broken braces, indented blocks.\n";
+ cout << endl;
+ cout << " --style=linux OR --style=knf OR -A8\n";
+ cout << " Linux style formatting/indenting.\n";
+ cout << " Linux braces, minimum conditional indent is one-half indent.\n";
+ cout << endl;
+ cout << " --style=horstmann OR --style=run-in OR -A9\n";
+ cout << " Horstmann style formatting/indenting.\n";
+ cout << " Run-in braces, indented switches.\n";
+ cout << endl;
+ cout << " --style=1tbs OR --style=otbs OR -A10\n";
+ cout << " One True Brace Style formatting/indenting.\n";
+ cout << " Linux braces, add braces to all conditionals.\n";
+ cout << endl;
+ cout << " --style=google OR -A14\n";
+ cout << " Google style formatting/indenting.\n";
+ cout << " Attached braces, indented class modifiers.\n";
+ cout << endl;
+ cout << " --style=mozilla OR -A16\n";
+ cout << " Mozilla style formatting/indenting.\n";
+ cout << " Linux braces, with broken braces for structs and enums,\n";
+ cout << " and attached braces for namespaces.\n";
+ cout << endl;
+ cout << " --style=pico OR -A11\n";
+ cout << " Pico style formatting/indenting.\n";
+ cout << " Run-in opening braces and attached closing braces.\n";
+ cout << " Uses keep one line blocks and keep one line statements.\n";
+ cout << endl;
+ cout << " --style=lisp OR -A12\n";
+ cout << " Lisp style formatting/indenting.\n";
+ cout << " Attached opening braces and attached closing braces.\n";
+ cout << " Uses keep one line statements.\n";
+ cout << endl;
+ cout << "Tab Options:\n";
+ cout << "------------\n";
+ cout << " default indent option\n";
+ cout << " If no indentation option is set, the default\n";
+ cout << " option of 4 spaces per indent will be used.\n";
+ cout << endl;
+ cout << " --indent=spaces=# OR -s#\n";
+ cout << " Indent using # spaces per indent. Not specifying #\n";
+ cout << " will result in a default of 4 spaces per indent.\n";
+ cout << endl;
+ cout << " --indent=tab OR --indent=tab=# OR -t OR -t#\n";
+ cout << " Indent using tab characters, assuming that each\n";
+ cout << " indent is # spaces long. Not specifying # will result\n";
+ cout << " in a default assumption of 4 spaces per indent.\n";
+ cout << endl;
+ cout << " --indent=force-tab=# OR -T#\n";
+ cout << " Indent using tab characters, assuming that each\n";
+ cout << " indent is # spaces long. Force tabs to be used in areas\n";
+ cout << " AStyle would prefer to use spaces.\n";
+ cout << endl;
+ cout << " --indent=force-tab-x=# OR -xT#\n";
+ cout << " Allows the tab length to be set to a length that is different\n";
+ cout << " from the indent length. This may cause the indentation to be\n";
+ cout << " a mix of both spaces and tabs. This option sets the tab length.\n";
+ cout << endl;
+ cout << "Brace Modify Options:\n";
+ cout << "---------------------\n";
+ cout << " --attach-namespaces OR -xn\n";
+ cout << " Attach braces to a namespace statement.\n";
+ cout << endl;
+ cout << " --attach-classes OR -xc\n";
+ cout << " Attach braces to a class statement.\n";
+ cout << endl;
+ cout << " --attach-inlines OR -xl\n";
+ cout << " Attach braces to class inline function definitions.\n";
+ cout << endl;
+ cout << " --attach-extern-c OR -xk\n";
+ cout << " Attach braces to an extern \"C\" statement.\n";
+ cout << endl;
+ cout << " --attach-closing-while OR -xV\n";
+ cout << " Attach closing while of do-while to the closing brace.\n";
+ cout << endl;
+ cout << "Indentation Options:\n";
+ cout << "--------------------\n";
+ cout << " --indent-classes OR -C\n";
+ cout << " Indent 'class' blocks so that the entire block is indented.\n";
+ cout << endl;
+ cout << " --indent-modifiers OR -xG\n";
+ cout << " Indent 'class' access modifiers, 'public:', 'protected:' or\n";
+ cout << " 'private:', one half indent. The rest of the class is not\n";
+ cout << " indented. \n";
+ cout << endl;
+ cout << " --indent-switches OR -S\n";
+ cout << " Indent 'switch' blocks, so that the inner 'case XXX:'\n";
+ cout << " headers are indented in relation to the switch block.\n";
+ cout << endl;
+ cout << " --indent-cases OR -K\n";
+ cout << " Indent case blocks from the 'case XXX:' headers.\n";
+ cout << " Case statements not enclosed in blocks are NOT indented.\n";
+ cout << endl;
+ cout << " --indent-namespaces OR -N\n";
+ cout << " Indent the contents of namespace blocks.\n";
+ cout << endl;
+ cout << " --indent-after-parens OR -xU\n";
+ cout << " Indent, instead of align, continuation lines following lines\n";
+ cout << " that contain an opening paren '(' or an assignment '='. \n";
+ cout << endl;
+ cout << " --indent-continuation=# OR -xt#\n";
+ cout << " Indent continuation lines an additional # indents.\n";
+ cout << " The valid values are 0 thru 4 indents.\n";
+ cout << " The default value is 1 indent.\n";
+ cout << endl;
+ cout << " --indent-labels OR -L\n";
+ cout << " Indent labels so that they appear one indent less than\n";
+ cout << " the current indentation level, rather than being\n";
+ cout << " flushed completely to the left (which is the default).\n";
+ cout << endl;
+ cout << " --indent-preproc-block OR -xW\n";
+ cout << " Indent preprocessor blocks at brace level 0.\n";
+ cout << " Without this option the preprocessor block is not indented.\n";
+ cout << endl;
+ cout << " --indent-preproc-cond OR -xw\n";
+ cout << " Indent preprocessor conditional statements #if/#else/#endif\n";
+ cout << " to the same level as the source code.\n";
+ cout << endl;
+ cout << " --indent-preproc-define OR -w\n";
+ cout << " Indent multi-line preprocessor #define statements.\n";
+ cout << endl;
+ cout << " --indent-col1-comments OR -Y\n";
+ cout << " Indent line comments that start in column one.\n";
+ cout << endl;
+ cout << " --min-conditional-indent=# OR -m#\n";
+ cout << " Indent a minimal # spaces in a continuous conditional\n";
+ cout << " belonging to a conditional header.\n";
+ cout << " The valid values are:\n";
+ cout << " 0 - no minimal indent.\n";
+ cout << " 1 - indent at least one additional indent.\n";
+ cout << " 2 - indent at least two additional indents.\n";
+ cout << " 3 - indent at least one-half an additional indent.\n";
+ cout << " The default value is 2, two additional indents.\n";
+ cout << endl;
+ cout << " --max-continuation-indent=# OR -M#\n";
+ cout << " Indent a maximal # spaces in a continuation line,\n";
+ cout << " relative to the previous line.\n";
+ cout << " The valid values are 40 thru 120.\n";
+ cout << " The default value is 40.\n";
+ cout << endl;
+ cout << "Padding Options:\n";
+ cout << "----------------\n";
+ cout << " --break-blocks OR -f\n";
+ cout << " Insert empty lines around unrelated blocks, labels, classes, ...\n";
+ cout << endl;
+ cout << " --break-blocks=all OR -F\n";
+ cout << " Like --break-blocks, except also insert empty lines \n";
+ cout << " around closing headers (e.g. 'else', 'catch', ...).\n";
+ cout << endl;
+ cout << " --pad-oper OR -p\n";
+ cout << " Insert space padding around operators.\n";
+ cout << endl;
+ cout << " --pad-comma OR -xg\n";
+ cout << " Insert space padding after commas.\n";
+ cout << endl;
+ cout << " --pad-paren OR -P\n";
+ cout << " Insert space padding around parenthesis on both the outside\n";
+ cout << " and the inside.\n";
+ cout << endl;
+ cout << " --pad-paren-out OR -d\n";
+ cout << " Insert space padding around parenthesis on the outside only.\n";
+ cout << endl;
+ cout << " --pad-first-paren-out OR -xd\n";
+ cout << " Insert space padding around first parenthesis in a series on\n";
+ cout << " the outside only.\n";
+ cout << endl;
+ cout << " --pad-paren-in OR -D\n";
+ cout << " Insert space padding around parenthesis on the inside only.\n";
+ cout << endl;
+ cout << " --pad-header OR -H\n";
+ cout << " Insert space padding after paren headers (e.g. 'if', 'for'...).\n";
+ cout << endl;
+ cout << " --unpad-paren OR -U\n";
+ cout << " Remove unnecessary space padding around parenthesis. This\n";
+ cout << " can be used in combination with the 'pad' options above.\n";
+ cout << endl;
+ cout << " --delete-empty-lines OR -xd\n";
+ cout << " Delete empty lines within a function or method.\n";
+ cout << " It will NOT delete lines added by the break-blocks options.\n";
+ cout << endl;
+ cout << " --fill-empty-lines OR -E\n";
+ cout << " Fill empty lines with the white space of their\n";
+ cout << " previous lines.\n";
+ cout << endl;
+ cout << " --align-pointer=type OR -k1\n";
+ cout << " --align-pointer=middle OR -k2\n";
+ cout << " --align-pointer=name OR -k3\n";
+ cout << " Attach a pointer or reference operator (*, &, or ^) to either\n";
+ cout << " the operator type (left), middle, or operator name (right).\n";
+ cout << " To align the reference separately use --align-reference.\n";
+ cout << endl;
+ cout << " --align-reference=none OR -W0\n";
+ cout << " --align-reference=type OR -W1\n";
+ cout << " --align-reference=middle OR -W2\n";
+ cout << " --align-reference=name OR -W3\n";
+ cout << " Attach a reference operator (&) to either\n";
+ cout << " the operator type (left), middle, or operator name (right).\n";
+ cout << " If not set, follow pointer alignment.\n";
+ cout << endl;
+ cout << "Formatting Options:\n";
+ cout << "-------------------\n";
+ cout << " --break-closing-braces OR -y\n";
+ cout << " Break braces before closing headers (e.g. 'else', 'catch', ...).\n";
+ cout << " Use with --style=java, --style=kr, --style=stroustrup,\n";
+ cout << " --style=linux, or --style=1tbs.\n";
+ cout << endl;
+ cout << " --break-elseifs OR -e\n";
+ cout << " Break 'else if()' statements into two different lines.\n";
+ cout << endl;
+ cout << " --break-one-line-headers OR -xb\n";
+ cout << " Break one line headers (e.g. 'if', 'while', 'else', ...) from a\n";
+ cout << " statement residing on the same line.\n";
+ cout << endl;
+ cout << " --add-braces OR -j\n";
+ cout << " Add braces to unbraced one line conditional statements.\n";
+ cout << endl;
+ cout << " --add-one-line-braces OR -J\n";
+ cout << " Add one line braces to unbraced one line conditional\n";
+ cout << " statements.\n";
+ cout << endl;
+ cout << " --remove-braces OR -xj\n";
+ cout << " Remove braces from a braced one line conditional statements.\n";
+ cout << endl;
+ cout << " --keep-one-line-blocks OR -O\n";
+ cout << " Don't break blocks residing completely on one line.\n";
+ cout << endl;
+ cout << " --keep-one-line-statements OR -o\n";
+ cout << " Don't break lines containing multiple statements into\n";
+ cout << " multiple single-statement lines.\n";
+ cout << endl;
+ cout << " --convert-tabs OR -c\n";
+ cout << " Convert tabs to the appropriate number of spaces.\n";
+ cout << endl;
+ cout << " --close-templates OR -xy\n";
+ cout << " Close ending angle brackets on template definitions.\n";
+ cout << endl;
+ cout << " --remove-comment-prefix OR -xp\n";
+ cout << " Remove the leading '*' prefix on multi-line comments and\n";
+ cout << " indent the comment text one indent.\n";
+ cout << endl;
+ cout << " --max-code-length=# OR -xC#\n";
+ cout << " --break-after-logical OR -xL\n";
+ cout << " max-code-length=# will break the line if it exceeds more than\n";
+ cout << " # characters. The valid values are 50 thru 200.\n";
+ cout << " If the line contains logical conditionals they will be placed\n";
+ cout << " first on the new line. The option break-after-logical will\n";
+ cout << " cause the logical conditional to be placed last on the\n";
+ cout << " previous line.\n";
+ cout << endl;
+ cout << " --mode=c\n";
+ cout << " Indent a C or C++ source file (this is the default).\n";
+ cout << endl;
+ cout << " --mode=java\n";
+ cout << " Indent a Java source file.\n";
+ cout << endl;
+ cout << " --mode=cs\n";
+ cout << " Indent a C# source file.\n";
+ cout << endl;
+ cout << "Objective-C Options:\n";
+ cout << "--------------------\n";
+ cout << " --pad-method-prefix OR -xQ\n";
+ cout << " Insert space padding after the '-' or '+' Objective-C\n";
+ cout << " method prefix.\n";
+ cout << endl;
+ cout << " --unpad-method-prefix OR -xR\n";
+ cout << " Remove all space padding after the '-' or '+' Objective-C\n";
+ cout << " method prefix.\n";
+ cout << endl;
+ cout << " --pad-return-type OR -xq\n";
+ cout << " Insert space padding after the Objective-C return type.\n";
+ cout << endl;
+ cout << " --unpad-return-type OR -xr\n";
+ cout << " Remove all space padding after the Objective-C return type.\n";
+ cout << endl;
+ cout << " --pad-param-type OR -xS\n";
+ cout << " Insert space padding after the Objective-C return type.\n";
+ cout << endl;
+ cout << " --unpad-param-type OR -xs\n";
+ cout << " Remove all space padding after the Objective-C return type.\n";
+ cout << endl;
+ cout << " --align-method-colon OR -xM\n";
+ cout << " Align the colons in an Objective-C method definition.\n";
+ cout << endl;
+ cout << " --pad-method-colon=none OR -xP\n";
+ cout << " --pad-method-colon=all OR -xP1\n";
+ cout << " --pad-method-colon=after OR -xP2\n";
+ cout << " --pad-method-colon=before OR -xP3\n";
+ cout << " Add or remove space padding before or after the colons in an\n";
+ cout << " Objective-C method call.\n";
+ cout << endl;
+ cout << "Other Options:\n";
+ cout << "--------------\n";
+ cout << " --suffix=####\n";
+ cout << " Append the suffix #### instead of '.orig' to original filename.\n";
+ cout << endl;
+ cout << " --suffix=none OR -n\n";
+ cout << " Do not retain a backup of the original file.\n";
+ cout << endl;
+ cout << " --recursive OR -r OR -R\n";
+ cout << " Process subdirectories recursively.\n";
+ cout << endl;
+ cout << " --dry-run\n";
+ cout << " Perform a trial run with no changes made to check for formatting.\n";
+ cout << endl;
+ cout << " --exclude=####\n";
+ cout << " Specify a file or directory #### to be excluded from processing.\n";
+ cout << endl;
+ cout << " --ignore-exclude-errors OR -i\n";
+ cout << " Allow processing to continue if there are errors in the exclude=####\n";
+ cout << " options. It will display the unmatched excludes.\n";
+ cout << endl;
+ cout << " --ignore-exclude-errors-x OR -xi\n";
+ cout << " Allow processing to continue if there are errors in the exclude=####\n";
+ cout << " options. It will NOT display the unmatched excludes.\n";
+ cout << endl;
+ cout << " --errors-to-stdout OR -X\n";
+ cout << " Print errors and help information to standard-output rather than\n";
+ cout << " to standard-error.\n";
+ cout << endl;
+ cout << " --preserve-date OR -Z\n";
+ cout << " Preserve the original file's date and time modified. The time\n";
+ cout << " modified will be changed a few micro seconds to force a compile.\n";
+ cout << endl;
+ cout << " --verbose OR -v\n";
+ cout << " Verbose mode. Extra informational messages will be displayed.\n";
+ cout << endl;
+ cout << " --formatted OR -Q\n";
+ cout << " Formatted display mode. Display only the files that have been\n";
+ cout << " formatted.\n";
+ cout << endl;
+ cout << " --quiet OR -q\n";
+ cout << " Quiet mode. Suppress all output except error messages.\n";
+ cout << endl;
+ cout << " --lineend=windows OR -z1\n";
+ cout << " --lineend=linux OR -z2\n";
+ cout << " --lineend=macold OR -z3\n";
+ cout << " Force use of the specified line end style. Valid options\n";
+ cout << " are windows (CRLF), linux (LF), and macold (CR).\n";
+ cout << endl;
+ cout << "Command Line Only:\n";
+ cout << "------------------\n";
+ cout << " --options=####\n";
+ cout << " Specify an options file #### to read and use.\n";
+ cout << endl;
+ cout << " --options=none\n";
+ cout << " Disable the default options file.\n";
+ cout << " Only the command-line parameters will be used.\n";
+ cout << endl;
+ cout << " --ascii OR -I\n";
+ cout << " The displayed output will be ascii characters only.\n";
+ cout << endl;
+ cout << " --version OR -V\n";
+ cout << " Print version number.\n";
+ cout << endl;
+ cout << " --help OR -h OR -?\n";
+ cout << " Print this help message.\n";
+ cout << endl;
+ cout << " --html OR -!\n";
+ cout << " Open the HTML help file \"astyle.html\" in the default browser.\n";
+ cout << " The documentation must be installed in the standard install path.\n";
+ cout << endl;
+ cout << " --html=####\n";
+ cout << " Open a HTML help file in the default browser using the file path\n";
+ cout << " ####. The path may include a directory path and a file name, or a\n";
+ cout << " file name only. Paths containing spaces must be enclosed in quotes.\n";
+ cout << endl;
+ cout << endl;
+}
+
+/**
+ * Process files in the fileNameVector.
+ */
+void ASConsole::processFiles()
+{
+ if (isVerbose)
+ printVerboseHeader();
+
+ clock_t startTime = clock(); // start time of file formatting
+
+ // loop thru input fileNameVector and process the files
+ for (size_t i = 0; i < fileNameVector.size(); i++)
+ {
+ getFilePaths(fileNameVector[i]);
+
+ // loop thru fileName vector formatting the files
+ for (size_t j = 0; j < fileName.size(); j++)
+ formatFile(fileName[j]);
+ }
+
+ // files are processed, display stats
+ if (isVerbose)
+ printVerboseStats(startTime);
+}
+
+// process options from the command line and options file
+// build the vectors fileNameVector, excludeVector, optionsVector, and fileOptionsVector
+void ASConsole::processOptions(const vector<string>& argvOptions)
+{
+ string arg;
+ bool ok = true;
+ bool shouldParseOptionsFile = true;
+
+ // get command line options
+ for (size_t i = 0; i < argvOptions.size(); i++)
+ {
+ arg = argvOptions[i];
+
+ if ( isOption(arg, "-I" )
+ || isOption(arg, "--ascii") )
+ {
+ useAscii = true;
+ setlocale(LC_ALL, "C"); // use English decimal indicator
+ localizer.setLanguageFromName("en");
+ }
+ else if ( isOption(arg, "--options=none") )
+ {
+ shouldParseOptionsFile = false;
+ }
+ else if ( isParamOption(arg, "--options=") )
+ {
+ optionsFileName = getParam(arg, "--options=");
+ optionsFileRequired = true;
+ if (optionsFileName.empty())
+ setOptionsFileName(" ");
+ }
+ else if ( isOption(arg, "-h")
+ || isOption(arg, "--help")
+ || isOption(arg, "-?") )
+ {
+ printHelp();
+ exit(EXIT_SUCCESS);
+ }
+ else if ( isOption(arg, "-!")
+ || isOption(arg, "--html") )
+ {
+ launchDefaultBrowser();
+ exit(EXIT_SUCCESS);
+ }
+ else if ( isParamOption(arg, "--html=") )
+ {
+ string htmlFilePath = getParam(arg, "--html=");
+ launchDefaultBrowser(htmlFilePath.c_str());
+ exit(EXIT_SUCCESS);
+ }
+ else if ( isOption(arg, "-V" )
+ || isOption(arg, "--version") )
+ {
+ printf("Artistic Style Version %s\n", g_version);
+ exit(EXIT_SUCCESS);
+ }
+ else if (arg[0] == '-')
+ {
+ optionsVector.emplace_back(arg);
+ }
+ else // file-name
+ {
+ standardizePath(arg);
+ fileNameVector.emplace_back(arg);
+ }
+ }
+
+ // get options file path and name
+ if (shouldParseOptionsFile)
+ {
+ if (optionsFileName.empty())
+ {
+ char* env = getenv("ARTISTIC_STYLE_OPTIONS");
+ if (env != nullptr)
+ setOptionsFileName(env);
+ }
+ if (optionsFileName.empty())
+ {
+ char* env = getenv("HOME");
+ if (env != nullptr)
+ setOptionsFileName(string(env) + "/.astylerc");
+ }
+ if (optionsFileName.empty())
+ {
+ char* env = getenv("USERPROFILE");
+ if (env != nullptr)
+ setOptionsFileName(string(env) + "/astylerc");
+ }
+ if (!optionsFileName.empty())
+ standardizePath(optionsFileName);
+ }
+
+ // create the options file vector and parse the options for errors
+ ASOptions options(formatter, *this);
+ if (!optionsFileName.empty())
+ {
+ ifstream optionsIn(optionsFileName.c_str());
+ if (optionsIn)
+ {
+ options.importOptions(optionsIn, fileOptionsVector);
+ ok = options.parseOptions(fileOptionsVector,
+ string(_("Invalid option file options:")));
+ }
+ else
+ {
+ if (optionsFileRequired)
+ error(_("Cannot open options file"), optionsFileName.c_str());
+ optionsFileName.clear();
+ }
+ optionsIn.close();
+ }
+ if (!ok)
+ {
+ (*errorStream) << options.getOptionErrors() << endl;
+ (*errorStream) << _("For help on options type 'astyle -h'") << endl;
+ error();
+ }
+
+ // parse the command line options vector for errors
+ ok = options.parseOptions(optionsVector,
+ string(_("Invalid command line options:")));
+ if (!ok)
+ {
+ (*errorStream) << options.getOptionErrors() << endl;
+ (*errorStream) << _("For help on options type 'astyle -h'") << endl;
+ error();
+ }
+}
+
+// remove a file and check for an error
+void ASConsole::removeFile(const char* fileName_, const char* errMsg) const
+{
+ if (remove(fileName_) != 0)
+ {
+ if (errno == ENOENT) // no file is OK
+ errno = 0;
+ if (errno)
+ {
+ perror("errno message");
+ error(errMsg, fileName_);
+ }
+ }
+}
+
+// rename a file and check for an error
+void ASConsole::renameFile(const char* oldFileName, const char* newFileName, const char* errMsg) const
+{
+ int result = rename(oldFileName, newFileName);
+ if (result != 0)
+ {
+ // if file still exists the remove needs more time - retry
+ if (errno == EEXIST)
+ {
+ errno = 0;
+ waitForRemove(newFileName);
+ result = rename(oldFileName, newFileName);
+ }
+ if (result != 0)
+ {
+ perror("errno message");
+ error(errMsg, oldFileName);
+ }
+ }
+}
+
+// make sure file separators are correct type (Windows or Linux)
+// remove ending file separator
+// remove beginning file separator if requested and NOT a complete file path
+void ASConsole::standardizePath(string& path, bool removeBeginningSeparator /*false*/) const
+{
+#ifdef __VMS
+ struct FAB fab;
+ struct NAML naml;
+ char less[NAML$C_MAXRSS];
+ char sess[NAM$C_MAXRSS];
+ int r0_status;
+
+ // If we are on a VMS system, translate VMS style filenames to unix
+ // style.
+ fab = cc$rms_fab;
+ fab.fab$l_fna = (char*) -1; // *NOPAD*
+ fab.fab$b_fns = 0;
+ fab.fab$l_naml = &naml;
+ naml = cc$rms_naml;
+ strcpy(sess, path.c_str());
+ naml.naml$l_long_filename = (char*)sess;
+ naml.naml$l_long_filename_size = path.length();
+ naml.naml$l_long_expand = less;
+ naml.naml$l_long_expand_alloc = sizeof(less);
+ naml.naml$l_esa = sess;
+ naml.naml$b_ess = sizeof(sess);
+ naml.naml$v_no_short_upcase = 1;
+ r0_status = sys$parse(&fab);
+ if (r0_status == RMS$_SYN)
+ {
+ error("File syntax error", path.c_str());
+ }
+ else
+ {
+ if (!$VMS_STATUS_SUCCESS(r0_status))
+ {
+ (void)lib$signal (r0_status);
+ }
+ }
+ less[naml.naml$l_long_expand_size - naml.naml$b_ver] = '\0';
+ sess[naml.naml$b_esl - naml.naml$b_ver] = '\0';
+ if (naml.naml$l_long_expand_size > naml.naml$b_esl)
+ {
+ path = decc$translate_vms (less);
+ }
+ else
+ {
+ path = decc$translate_vms(sess);
+ }
+#endif /* __VMS */
+
+ // make sure separators are correct type (Windows or Linux)
+ for (size_t i = 0; i < path.length(); i++)
+ {
+ i = path.find_first_of("/\\", i);
+ if (i == string::npos)
+ break;
+ path[i] = g_fileSeparator;
+ }
+ // remove beginning separator if requested
+ if (removeBeginningSeparator && (path[0] == g_fileSeparator))
+ path.erase(0, 1);
+}
+
+void ASConsole::printMsg(const char* msg, const string& data) const
+{
+ if (isQuiet)
+ return;
+ printf(msg, data.c_str());
+}
+
+void ASConsole::printSeparatingLine() const
+{
+ string line;
+ for (size_t i = 0; i < 60; i++)
+ line.append("-");
+ printMsg("%s\n", line);
+}
+
+void ASConsole::printVerboseHeader() const
+{
+ assert(isVerbose);
+ if (isQuiet)
+ return;
+ // get the date
+ time_t lt;
+ char str[20];
+ lt = time(nullptr);
+ struct tm* ptr = localtime(<);
+ strftime(str, 20, "%x", ptr);
+ // print the header
+ // 60 is the length of the separator in printSeparatingLine()
+ string header = "Artistic Style " + string(g_version);
+ size_t numSpaces = 60 - header.length() - strlen(str);
+ header.append(numSpaces, ' ');
+ header.append(str);
+ header.append("\n");
+ printf("%s", header.c_str());
+ // print options file
+ if (!optionsFileName.empty())
+ printf(_("Using default options file %s\n"), optionsFileName.c_str());
+}
+
+void ASConsole::printVerboseStats(clock_t startTime) const
+{
+ assert(isVerbose);
+ if (isQuiet)
+ return;
+ if (hasWildcard)
+ printSeparatingLine();
+ string formatted = getNumberFormat(filesFormatted);
+ string unchanged = getNumberFormat(filesUnchanged);
+ printf(_(" %s formatted %s unchanged "), formatted.c_str(), unchanged.c_str());
+
+ // show processing time
+ clock_t stopTime = clock();
+ double secs = (stopTime - startTime) / double (CLOCKS_PER_SEC);
+ if (secs < 60)
+ {
+ if (secs < 2.0)
+ printf("%.2f", secs);
+ else if (secs < 20.0)
+ printf("%.1f", secs);
+ else
+ printf("%.0f", secs);
+ printf("%s", _(" seconds "));
+ }
+ else
+ {
+ // show minutes and seconds if time is greater than one minute
+ int min = (int) secs / 60;
+ secs -= min * 60;
+ int minsec = int (secs + .5);
+ printf(_("%d min %d sec "), min, minsec);
+ }
+
+ string lines = getNumberFormat(linesOut);
+ printf(_("%s lines\n"), lines.c_str());
+}
+
+void ASConsole::sleep(int seconds) const
+{
+ clock_t endwait;
+ endwait = clock_t (clock () + seconds * CLOCKS_PER_SEC);
+ while (clock() < endwait) {}
+}
+
+bool ASConsole::stringEndsWith(const string& str, const string& suffix) const
+{
+ int strIndex = (int) str.length() - 1;
+ int suffixIndex = (int) suffix.length() - 1;
+
+ while (strIndex >= 0 && suffixIndex >= 0)
+ {
+ if (tolower(str[strIndex]) != tolower(suffix[suffixIndex]))
+ return false;
+
+ --strIndex;
+ --suffixIndex;
+ }
+ // suffix longer than string
+ if (strIndex < 0 && suffixIndex >= 0)
+ return false;
+ return true;
+}
+
+void ASConsole::updateExcludeVector(const string& suffixParam)
+{
+ excludeVector.emplace_back(suffixParam);
+ standardizePath(excludeVector.back(), true);
+ excludeHitsVector.push_back(false);
+}
+
+int ASConsole::waitForRemove(const char* newFileName) const
+{
+ struct stat stBuf;
+ int seconds;
+ // sleep a max of 20 seconds for the remove
+ for (seconds = 1; seconds <= 20; seconds++)
+ {
+ sleep(1);
+ if (stat(newFileName, &stBuf) != 0)
+ break;
+ }
+ errno = 0;
+ return seconds;
+}
+
+// From The Code Project http://www.codeproject.com/string/wildcmp.asp
+// Written by Jack Handy - jakkhandy@hotmail.com
+// Modified to compare case insensitive for Windows
+int ASConsole::wildcmp(const char* wild, const char* data) const
+{
+ const char* cp = nullptr, *mp = nullptr;
+ bool cmpval;
+
+ while ((*data) && (*wild != '*'))
+ {
+ if (!g_isCaseSensitive)
+ cmpval = (tolower(*wild) != tolower(*data)) && (*wild != '?');
+ else
+ cmpval = (*wild != *data) && (*wild != '?');
+
+ if (cmpval)
+ {
+ return 0;
+ }
+ wild++;
+ data++;
+ }
+
+ while (*data)
+ {
+ if (*wild == '*')
+ {
+ if (!*++wild)
+ {
+ return 1;
+ }
+ mp = wild;
+ cp = data + 1;
+ }
+ else
+ {
+ if (!g_isCaseSensitive)
+ cmpval = (tolower(*wild) == tolower(*data) || (*wild == '?'));
+ else
+ cmpval = (*wild == *data) || (*wild == '?');
+
+ if (cmpval)
+ {
+ wild++;
+ data++;
+ }
+ else
+ {
+ wild = mp;
+ data = cp++;
+ }
+ }
+ }
+
+ while (*wild == '*')
+ {
+ wild++;
+ }
+ return !*wild;
+}
+
+void ASConsole::writeFile(const string& fileName_, FileEncoding encoding, ostringstream& out) const
+{
+ // save date accessed and date modified of original file
+ struct stat stBuf;
+ bool statErr = false;
+ if (stat(fileName_.c_str(), &stBuf) == -1)
+ statErr = true;
+
+ // create a backup
+ if (!noBackup)
+ {
+ string origFileName = fileName_ + origSuffix;
+ removeFile(origFileName.c_str(), "Cannot remove pre-existing backup file");
+ renameFile(fileName_.c_str(), origFileName.c_str(), "Cannot create backup file");
+ }
+
+ // write the output file
+ ofstream fout(fileName_.c_str(), ios::binary | ios::trunc);
+ if (!fout)
+ error("Cannot open output file", fileName_.c_str());
+ if (encoding == UTF_16LE || encoding == UTF_16BE)
+ {
+ // convert utf-8 to utf-16
+ bool isBigEndian = (encoding == UTF_16BE);
+ size_t utf16Size = utf8_16.utf16LengthFromUtf8(out.str().c_str(), out.str().length());
+ char* utf16Out = new char[utf16Size];
+ size_t utf16Len = utf8_16.utf8ToUtf16(const_cast<char*>(out.str().c_str()),
+ out.str().length(), isBigEndian, utf16Out);
+ assert(utf16Len == utf16Size);
+ fout << string(utf16Out, utf16Len);
+ delete[] utf16Out;
+ }
+ else
+ fout << out.str();
+
+ fout.close();
+
+ // change date modified to original file date
+ // Embarcadero must be linked with cw32mt not cw32
+ if (preserveDate)
+ {
+ if (!statErr)
+ {
+ struct utimbuf outBuf;
+ outBuf.actime = stBuf.st_atime;
+ // add ticks so 'make' will recognize a change
+ // Visual Studio 2008 needs more than 1
+ outBuf.modtime = stBuf.st_mtime + 10;
+ if (utime(fileName_.c_str(), &outBuf) == -1)
+ statErr = true;
+ }
+ if (statErr)
+ {
+ perror("errno message");
+ (*errorStream) << "********* Cannot preserve file date" << endl;
+ }
+ }
+}
+
+#else // ASTYLE_LIB
+
+//-----------------------------------------------------------------------------
+// ASLibrary class
+// used by shared object (DLL) calls
+//-----------------------------------------------------------------------------
+
+utf16_t* ASLibrary::formatUtf16(const utf16_t* pSourceIn, // the source to be formatted
+ const utf16_t* pOptions, // AStyle options
+ fpError fpErrorHandler, // error handler function
+ fpAlloc fpMemoryAlloc) const // memory allocation function)
+{
+ const char* utf8In = convertUtf16ToUtf8(pSourceIn);
+ if (utf8In == nullptr)
+ {
+ fpErrorHandler(121, "Cannot convert input utf-16 to utf-8.");
+ return nullptr;
+ }
+ const char* utf8Options = convertUtf16ToUtf8(pOptions);
+ if (utf8Options == nullptr)
+ {
+ delete[] utf8In;
+ fpErrorHandler(122, "Cannot convert options utf-16 to utf-8.");
+ return nullptr;
+ }
+ // call the Artistic Style formatting function
+ // cannot use the callers memory allocation here
+ char* utf8Out = AStyleMain(utf8In,
+ utf8Options,
+ fpErrorHandler,
+ ASLibrary::tempMemoryAllocation);
+ // finished with these
+ delete[] utf8In;
+ delete[] utf8Options;
+ utf8In = nullptr;
+ utf8Options = nullptr;
+ // AStyle error has already been sent
+ if (utf8Out == nullptr)
+ return nullptr;
+ // convert text to wide char and return it
+ utf16_t* utf16Out = convertUtf8ToUtf16(utf8Out, fpMemoryAlloc);
+ delete[] utf8Out;
+ utf8Out = nullptr;
+ if (utf16Out == nullptr)
+ {
+ fpErrorHandler(123, "Cannot convert output utf-8 to utf-16.");
+ return nullptr;
+ }
+ return utf16Out;
+}
+
+// STATIC method to allocate temporary memory for AStyle formatting.
+// The data will be converted before being returned to the calling program.
+char* STDCALL ASLibrary::tempMemoryAllocation(unsigned long memoryNeeded)
+{
+ char* buffer = new (nothrow) char[memoryNeeded];
+ return buffer;
+}
+
+/**
+ * Convert utf-8 strings to utf16 strings.
+ * Memory is allocated by the calling program memory allocation function.
+ * The calling function must check for errors.
+ */
+utf16_t* ASLibrary::convertUtf8ToUtf16(const char* utf8In, fpAlloc fpMemoryAlloc) const
+{
+ if (utf8In == nullptr)
+ return nullptr;
+ char* data = const_cast<char*>(utf8In);
+ size_t dataSize = strlen(utf8In);
+ bool isBigEndian = utf8_16.getBigEndian();
+ // return size is in number of CHARs, not utf16_t
+ size_t utf16Size = (utf8_16.utf16LengthFromUtf8(data, dataSize) + sizeof(utf16_t));
+ char* utf16Out = fpMemoryAlloc((long)utf16Size);
+ if (utf16Out == nullptr)
+ return nullptr;
+#ifdef NDEBUG
+ utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
+#else
+ size_t utf16Len = utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
+ assert(utf16Len == utf16Size);
+#endif
+ assert(utf16Size == (utf8_16.utf16len(reinterpret_cast<utf16_t*>(utf16Out)) + 1) * sizeof(utf16_t));
+ return reinterpret_cast<utf16_t*>(utf16Out);
+}
+
+/**
+ * Convert utf16 strings to utf-8.
+ * The calling function must check for errors and delete the
+ * allocated memory.
+ */
+char* ASLibrary::convertUtf16ToUtf8(const utf16_t* utf16In) const
+{
+ if (utf16In == nullptr)
+ return nullptr;
+ char* data = reinterpret_cast<char*>(const_cast<utf16_t*>(utf16In));
+ // size must be in chars
+ size_t dataSize = utf8_16.utf16len(utf16In) * sizeof(utf16_t);
+ bool isBigEndian = utf8_16.getBigEndian();
+ size_t utf8Size = utf8_16.utf8LengthFromUtf16(data, dataSize, isBigEndian) + 1;
+ char* utf8Out = new (nothrow) char[utf8Size];
+ if (utf8Out == nullptr)
+ return nullptr;
+#ifdef NDEBUG
+ utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
+#else
+ size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
+ assert(utf8Len == utf8Size);
+#endif
+ assert(utf8Size == strlen(utf8Out) + 1);
+ return utf8Out;
+}
+
+#endif // ASTYLE_LIB
+
+//-----------------------------------------------------------------------------
+// ASOptions class
+// used by both console and library builds
+//-----------------------------------------------------------------------------
+
+#ifdef ASTYLE_LIB
+ASOptions::ASOptions(ASFormatter& formatterArg)
+ : formatter(formatterArg)
+{ }
+#else
+ASOptions::ASOptions(ASFormatter& formatterArg, ASConsole& consoleArg)
+ : formatter(formatterArg), console(consoleArg)
+{ }
+#endif
+
+/**
+ * parse the options vector
+ * optionsVector can be either a fileOptionsVector (options file) or an optionsVector (command line)
+ *
+ * @return true if no errors, false if errors
+ */
+bool ASOptions::parseOptions(vector<string>& optionsVector, const string& errorInfo)
+{
+ vector<string>::iterator option;
+ string arg, subArg;
+ optionErrors.clear();
+
+ for (option = optionsVector.begin(); option != optionsVector.end(); ++option)
+ {
+ arg = *option;
+
+ if (arg.compare(0, 2, "--") == 0)
+ parseOption(arg.substr(2), errorInfo);
+ else if (arg[0] == '-')
+ {
+ size_t i;
+
+ for (i = 1; i < arg.length(); ++i)
+ {
+ if (i > 1
+ && isalpha((unsigned char)arg[i])
+ && arg[i - 1] != 'x')
+ {
+ // parse the previous option in subArg
+ parseOption(subArg, errorInfo);
+ subArg = "";
+ }
+ // append the current option to subArg
+ subArg.append(1, arg[i]);
+ }
+ // parse the last option
+ parseOption(subArg, errorInfo);
+ subArg = "";
+ }
+ else
+ {
+ parseOption(arg, errorInfo);
+ subArg = "";
+ }
+ }
+ if (optionErrors.str().length() > 0)
+ return false;
+ return true;
+}
+
+void ASOptions::parseOption(const string& arg, const string& errorInfo)
+{
+ if ( isOption(arg, "style=allman") || isOption(arg, "style=bsd") || isOption(arg, "style=break") )
+ {
+ formatter.setFormattingStyle(STYLE_ALLMAN);
+ }
+ else if ( isOption(arg, "style=java") || isOption(arg, "style=attach") )
+ {
+ formatter.setFormattingStyle(STYLE_JAVA);
+ }
+ else if ( isOption(arg, "style=k&r") || isOption(arg, "style=kr") || isOption(arg, "style=k/r") )
+ {
+ formatter.setFormattingStyle(STYLE_KR);
+ }
+ else if ( isOption(arg, "style=stroustrup") )
+ {
+ formatter.setFormattingStyle(STYLE_STROUSTRUP);
+ }
+ else if ( isOption(arg, "style=whitesmith") )
+ {
+ formatter.setFormattingStyle(STYLE_WHITESMITH);
+ }
+ else if ( isOption(arg, "style=vtk") )
+ {
+ formatter.setFormattingStyle(STYLE_VTK);
+ }
+ else if ( isOption(arg, "style=banner") )
+ {
+ formatter.setFormattingStyle(STYLE_BANNER);
+ }
+ else if ( isOption(arg, "style=gnu") )
+ {
+ formatter.setFormattingStyle(STYLE_GNU);
+ }
+ else if ( isOption(arg, "style=linux") || isOption(arg, "style=knf") )
+ {
+ formatter.setFormattingStyle(STYLE_LINUX);
+ }
+ else if ( isOption(arg, "style=horstmann") || isOption(arg, "style=run-in") )
+ {
+ formatter.setFormattingStyle(STYLE_HORSTMANN);
+ }
+ else if ( isOption(arg, "style=1tbs") || isOption(arg, "style=otbs") )
+ {
+ formatter.setFormattingStyle(STYLE_1TBS);
+ }
+ else if ( isOption(arg, "style=google") )
+ {
+ formatter.setFormattingStyle(STYLE_GOOGLE);
+ }
+ else if (isOption(arg, "style=mozilla"))
+ {
+ formatter.setFormattingStyle(STYLE_MOZILLA);
+ }
+ else if ( isOption(arg, "style=pico") )
+ {
+ formatter.setFormattingStyle(STYLE_PICO);
+ }
+ else if ( isOption(arg, "style=lisp") || isOption(arg, "style=python") )
+ {
+ formatter.setFormattingStyle(STYLE_LISP);
+ }
+ else if ( isParamOption(arg, "A") )
+ {
+ int style = 0;
+ string styleParam = getParam(arg, "A");
+ if (styleParam.length() > 0)
+ style = atoi(styleParam.c_str());
+ if (style == 1)
+ formatter.setFormattingStyle(STYLE_ALLMAN);
+ else if (style == 2)
+ formatter.setFormattingStyle(STYLE_JAVA);
+ else if (style == 3)
+ formatter.setFormattingStyle(STYLE_KR);
+ else if (style == 4)
+ formatter.setFormattingStyle(STYLE_STROUSTRUP);
+ else if (style == 5)
+ formatter.setFormattingStyle(STYLE_WHITESMITH);
+ else if (style == 6)
+ formatter.setFormattingStyle(STYLE_BANNER);
+ else if (style == 7)
+ formatter.setFormattingStyle(STYLE_GNU);
+ else if (style == 8)
+ formatter.setFormattingStyle(STYLE_LINUX);
+ else if (style == 9)
+ formatter.setFormattingStyle(STYLE_HORSTMANN);
+ else if (style == 10)
+ formatter.setFormattingStyle(STYLE_1TBS);
+ else if (style == 11)
+ formatter.setFormattingStyle(STYLE_PICO);
+ else if (style == 12)
+ formatter.setFormattingStyle(STYLE_LISP);
+ else if (style == 14)
+ formatter.setFormattingStyle(STYLE_GOOGLE);
+ else if (style == 15)
+ formatter.setFormattingStyle(STYLE_VTK);
+ else if (style == 16)
+ formatter.setFormattingStyle(STYLE_MOZILLA);
+ else
+ isOptionError(arg, errorInfo);
+ }
+ // must check for mode=cs before mode=c !!!
+ else if ( isOption(arg, "mode=cs") )
+ {
+ formatter.setSharpStyle();
+ formatter.setModeManuallySet(true);
+ }
+ else if ( isOption(arg, "mode=c") )
+ {
+ formatter.setCStyle();
+ formatter.setModeManuallySet(true);
+ }
+ else if ( isOption(arg, "mode=java") )
+ {
+ formatter.setJavaStyle();
+ formatter.setModeManuallySet(true);
+ }
+ else if ( isParamOption(arg, "t", "indent=tab=") )
+ {
+ int spaceNum = 4;
+ string spaceNumParam = getParam(arg, "t", "indent=tab=");
+ if (spaceNumParam.length() > 0)
+ spaceNum = atoi(spaceNumParam.c_str());
+ if (spaceNum < 2 || spaceNum > 20)
+ isOptionError(arg, errorInfo);
+ else
+ {
+ formatter.setTabIndentation(spaceNum, false);
+ }
+ }
+ else if ( isOption(arg, "indent=tab") )
+ {
+ formatter.setTabIndentation(4);
+ }
+ else if ( isParamOption(arg, "T", "indent=force-tab=") )
+ {
+ int spaceNum = 4;
+ string spaceNumParam = getParam(arg, "T", "indent=force-tab=");
+ if (spaceNumParam.length() > 0)
+ spaceNum = atoi(spaceNumParam.c_str());
+ if (spaceNum < 2 || spaceNum > 20)
+ isOptionError(arg, errorInfo);
+ else
+ {
+ formatter.setTabIndentation(spaceNum, true);
+ }
+ }
+ else if ( isOption(arg, "indent=force-tab") )
+ {
+ formatter.setTabIndentation(4, true);
+ }
+ else if ( isParamOption(arg, "xT", "indent=force-tab-x=") )
+ {
+ int tabNum = 8;
+ string tabNumParam = getParam(arg, "xT", "indent=force-tab-x=");
+ if (tabNumParam.length() > 0)
+ tabNum = atoi(tabNumParam.c_str());
+ if (tabNum < 2 || tabNum > 20)
+ isOptionError(arg, errorInfo);
+ else
+ {
+ formatter.setForceTabXIndentation(tabNum);
+ }
+ }
+ else if ( isOption(arg, "indent=force-tab-x") )
+ {
+ formatter.setForceTabXIndentation(8);
+ }
+ else if ( isParamOption(arg, "s", "indent=spaces=") )
+ {
+ int spaceNum = 4;
+ string spaceNumParam = getParam(arg, "s", "indent=spaces=");
+ if (spaceNumParam.length() > 0)
+ spaceNum = atoi(spaceNumParam.c_str());
+ if (spaceNum < 2 || spaceNum > 20)
+ isOptionError(arg, errorInfo);
+ else
+ {
+ formatter.setSpaceIndentation(spaceNum);
+ }
+ }
+ else if ( isOption(arg, "indent=spaces") )
+ {
+ formatter.setSpaceIndentation(4);
+ }
+ else if (isParamOption(arg, "xt", "indent-continuation="))
+ {
+ int contIndent = 1;
+ string contIndentParam = getParam(arg, "xt", "indent-continuation=");
+ if (contIndentParam.length() > 0)
+ contIndent = atoi(contIndentParam.c_str());
+ if (contIndent < 0)
+ isOptionError(arg, errorInfo);
+ else if (contIndent > 4)
+ isOptionError(arg, errorInfo);
+ else
+ formatter.setContinuationIndentation(contIndent);
+ }
+ else if ( isParamOption(arg, "m", "min-conditional-indent=") )
+ {
+ int minIndent = MINCOND_TWO;
+ string minIndentParam = getParam(arg, "m", "min-conditional-indent=");
+ if (minIndentParam.length() > 0)
+ minIndent = atoi(minIndentParam.c_str());
+ if (minIndent >= MINCOND_END)
+ isOptionError(arg, errorInfo);
+ else
+ formatter.setMinConditionalIndentOption(minIndent);
+ }
+ else if ( isParamOption(arg, "M", "max-continuation-indent=") )
+ {
+ int maxIndent = 40;
+ string maxIndentParam = getParam(arg, "M", "max-continuation-indent=");
+ if (maxIndentParam.length() > 0)
+ maxIndent = atoi(maxIndentParam.c_str());
+ if (maxIndent < 40)
+ isOptionError(arg, errorInfo);
+ else if (maxIndent > 120)
+ isOptionError(arg, errorInfo);
+ else
+ formatter.setMaxContinuationIndentLength(maxIndent);
+ }
+ else if ( isOption(arg, "N", "indent-namespaces") )
+ {
+ formatter.setNamespaceIndent(true);
+ }
+ else if ( isOption(arg, "C", "indent-classes") )
+ {
+ formatter.setClassIndent(true);
+ }
+ else if ( isOption(arg, "xG", "indent-modifiers") )
+ {
+ formatter.setModifierIndent(true);
+ }
+ else if ( isOption(arg, "S", "indent-switches") )
+ {
+ formatter.setSwitchIndent(true);
+ }
+ else if ( isOption(arg, "K", "indent-cases") )
+ {
+ formatter.setCaseIndent(true);
+ }
+ else if ( isOption(arg, "xU", "indent-after-parens") )
+ {
+ formatter.setAfterParenIndent(true);
+ }
+ else if ( isOption(arg, "L", "indent-labels") )
+ {
+ formatter.setLabelIndent(true);
+ }
+ else if (isOption(arg, "xW", "indent-preproc-block"))
+ {
+ formatter.setPreprocBlockIndent(true);
+ }
+ else if ( isOption(arg, "w", "indent-preproc-define") )
+ {
+ formatter.setPreprocDefineIndent(true);
+ }
+ else if ( isOption(arg, "xw", "indent-preproc-cond") )
+ {
+ formatter.setPreprocConditionalIndent(true);
+ }
+ else if ( isOption(arg, "y", "break-closing-braces") )
+ {
+ formatter.setBreakClosingHeaderBracesMode(true);
+ }
+ else if ( isOption(arg, "O", "keep-one-line-blocks") )
+ {
+ formatter.setBreakOneLineBlocksMode(false);
+ }
+ else if ( isOption(arg, "o", "keep-one-line-statements") )
+ {
+ formatter.setBreakOneLineStatementsMode(false);
+ }
+ else if ( isOption(arg, "P", "pad-paren") )
+ {
+ formatter.setParensOutsidePaddingMode(true);
+ formatter.setParensInsidePaddingMode(true);
+ }
+ else if ( isOption(arg, "d", "pad-paren-out") )
+ {
+ formatter.setParensOutsidePaddingMode(true);
+ }
+ else if ( isOption(arg, "xd", "pad-first-paren-out") )
+ {
+ formatter.setParensFirstPaddingMode(true);
+ }
+ else if ( isOption(arg, "D", "pad-paren-in") )
+ {
+ formatter.setParensInsidePaddingMode(true);
+ }
+ else if ( isOption(arg, "H", "pad-header") )
+ {
+ formatter.setParensHeaderPaddingMode(true);
+ }
+ else if ( isOption(arg, "U", "unpad-paren") )
+ {
+ formatter.setParensUnPaddingMode(true);
+ }
+ else if ( isOption(arg, "p", "pad-oper") )
+ {
+ formatter.setOperatorPaddingMode(true);
+ }
+ else if (isOption(arg, "xg", "pad-comma"))
+ {
+ formatter.setCommaPaddingMode(true);
+ }
+ else if ( isOption(arg, "xe", "delete-empty-lines") )
+ {
+ formatter.setDeleteEmptyLinesMode(true);
+ }
+ else if ( isOption(arg, "E", "fill-empty-lines") )
+ {
+ formatter.setEmptyLineFill(true);
+ }
+ else if ( isOption(arg, "c", "convert-tabs") )
+ {
+ formatter.setTabSpaceConversionMode(true);
+ }
+ else if ( isOption(arg, "xy", "close-templates") )
+ {
+ formatter.setCloseTemplatesMode(true);
+ }
+ else if ( isOption(arg, "F", "break-blocks=all") )
+ {
+ formatter.setBreakBlocksMode(true);
+ formatter.setBreakClosingHeaderBlocksMode(true);
+ }
+ else if ( isOption(arg, "f", "break-blocks") )
+ {
+ formatter.setBreakBlocksMode(true);
+ }
+ else if ( isOption(arg, "e", "break-elseifs") )
+ {
+ formatter.setBreakElseIfsMode(true);
+ }
+ else if ( isOption(arg, "xb", "break-one-line-headers") )
+ {
+ formatter.setBreakOneLineHeadersMode(true);
+ }
+ else if ( isOption(arg, "j", "add-braces") )
+ {
+ formatter.setAddBracesMode(true);
+ }
+ else if ( isOption(arg, "J", "add-one-line-braces") )
+ {
+ formatter.setAddOneLineBracesMode(true);
+ }
+ else if ( isOption(arg, "xj", "remove-braces") )
+ {
+ formatter.setRemoveBracesMode(true);
+ }
+ else if ( isOption(arg, "Y", "indent-col1-comments") )
+ {
+ formatter.setIndentCol1CommentsMode(true);
+ }
+ else if ( isOption(arg, "align-pointer=type") )
+ {
+ formatter.setPointerAlignment(PTR_ALIGN_TYPE);
+ }
+ else if ( isOption(arg, "align-pointer=middle") )
+ {
+ formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
+ }
+ else if ( isOption(arg, "align-pointer=name") )
+ {
+ formatter.setPointerAlignment(PTR_ALIGN_NAME);
+ }
+ else if ( isParamOption(arg, "k") )
+ {
+ int align = 0;
+ string styleParam = getParam(arg, "k");
+ if (styleParam.length() > 0)
+ align = atoi(styleParam.c_str());
+ if (align < 1 || align > 3)
+ isOptionError(arg, errorInfo);
+ else if (align == 1)
+ formatter.setPointerAlignment(PTR_ALIGN_TYPE);
+ else if (align == 2)
+ formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
+ else if (align == 3)
+ formatter.setPointerAlignment(PTR_ALIGN_NAME);
+ }
+ else if ( isOption(arg, "align-reference=none") )
+ {
+ formatter.setReferenceAlignment(REF_ALIGN_NONE);
+ }
+ else if ( isOption(arg, "align-reference=type") )
+ {
+ formatter.setReferenceAlignment(REF_ALIGN_TYPE);
+ }
+ else if ( isOption(arg, "align-reference=middle") )
+ {
+ formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
+ }
+ else if ( isOption(arg, "align-reference=name") )
+ {
+ formatter.setReferenceAlignment(REF_ALIGN_NAME);
+ }
+ else if ( isParamOption(arg, "W") )
+ {
+ int align = 0;
+ string styleParam = getParam(arg, "W");
+ if (styleParam.length() > 0)
+ align = atoi(styleParam.c_str());
+ if (align < 0 || align > 3)
+ isOptionError(arg, errorInfo);
+ else if (align == 0)
+ formatter.setReferenceAlignment(REF_ALIGN_NONE);
+ else if (align == 1)
+ formatter.setReferenceAlignment(REF_ALIGN_TYPE);
+ else if (align == 2)
+ formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
+ else if (align == 3)
+ formatter.setReferenceAlignment(REF_ALIGN_NAME);
+ }
+ else if ( isParamOption(arg, "max-code-length=") )
+ {
+ int maxLength = 50;
+ string maxLengthParam = getParam(arg, "max-code-length=");
+ if (maxLengthParam.length() > 0)
+ maxLength = atoi(maxLengthParam.c_str());
+ if (maxLength < 50)
+ isOptionError(arg, errorInfo);
+ else if (maxLength > 200)
+ isOptionError(arg, errorInfo);
+ else
+ formatter.setMaxCodeLength(maxLength);
+ }
+ else if ( isParamOption(arg, "xC") )
+ {
+ int maxLength = 50;
+ string maxLengthParam = getParam(arg, "xC");
+ if (maxLengthParam.length() > 0)
+ maxLength = atoi(maxLengthParam.c_str());
+ if (maxLength > 200)
+ isOptionError(arg, errorInfo);
+ else
+ formatter.setMaxCodeLength(maxLength);
+ }
+ else if ( isOption(arg, "xL", "break-after-logical") )
+ {
+ formatter.setBreakAfterMode(true);
+ }
+ else if ( isOption(arg, "xc", "attach-classes") )
+ {
+ formatter.setAttachClass(true);
+ }
+ else if ( isOption(arg, "xV", "attach-closing-while") )
+ {
+ formatter.setAttachClosingWhile(true);
+ }
+ else if ( isOption(arg, "xk", "attach-extern-c") )
+ {
+ formatter.setAttachExternC(true);
+ }
+ else if ( isOption(arg, "xn", "attach-namespaces") )
+ {
+ formatter.setAttachNamespace(true);
+ }
+ else if ( isOption(arg, "xl", "attach-inlines") )
+ {
+ formatter.setAttachInline(true);
+ }
+ else if ( isOption(arg, "xp", "remove-comment-prefix") )
+ {
+ formatter.setStripCommentPrefix(true);
+ }
+ // Objective-C options
+ else if ( isOption(arg, "xQ", "pad-method-prefix") )
+ {
+ formatter.setMethodPrefixPaddingMode(true);
+ }
+ else if ( isOption(arg, "xR", "unpad-method-prefix") )
+ {
+ formatter.setMethodPrefixUnPaddingMode(true);
+ }
+ else if (isOption(arg, "xq", "pad-return-type"))
+ {
+ formatter.setReturnTypePaddingMode(true);
+ }
+ else if (isOption(arg, "xr", "unpad-return-type"))
+ {
+ formatter.setReturnTypeUnPaddingMode(true);
+ }
+ else if (isOption(arg, "xS", "pad-param-type"))
+ {
+ formatter.setParamTypePaddingMode(true);
+ }
+ else if (isOption(arg, "xs", "unpad-param-type"))
+ {
+ formatter.setParamTypeUnPaddingMode(true);
+ }
+ else if (isOption(arg, "xM", "align-method-colon"))
+ {
+ formatter.setAlignMethodColon(true);
+ }
+ else if ( isOption(arg, "xP0", "pad-method-colon=none") )
+ {
+ formatter.setObjCColonPaddingMode(COLON_PAD_NONE);
+ }
+ else if ( isOption(arg, "xP1", "pad-method-colon=all") )
+ {
+ formatter.setObjCColonPaddingMode(COLON_PAD_ALL);
+ }
+ else if ( isOption(arg, "xP2", "pad-method-colon=after") )
+ {
+ formatter.setObjCColonPaddingMode(COLON_PAD_AFTER);
+ }
+ else if ( isOption(arg, "xP3", "pad-method-colon=before") )
+ {
+ formatter.setObjCColonPaddingMode(COLON_PAD_BEFORE);
+ }
+ // depreciated options ////////////////////////////////////////////////////////////////////////
+ else if ( isOption(arg, "indent-preprocessor") ) // depreciated release 2.04
+ {
+ formatter.setPreprocDefineIndent(true);
+ }
+ else if ( isOption(arg, "style=ansi") ) // depreciated release 2.05
+ {
+ formatter.setFormattingStyle(STYLE_ALLMAN);
+ }
+ // depreciated in release 3.0 /////////////////////////////////////////////////////////////////
+ else if ( isOption(arg, "break-closing-brackets") ) // depreciated release 3.0
+ {
+ formatter.setBreakClosingHeaderBracketsMode(true);
+ }
+ else if ( isOption(arg, "add-brackets") ) // depreciated release 3.0
+ {
+ formatter.setAddBracketsMode(true);
+ }
+ else if ( isOption(arg, "add-one-line-brackets") ) // depreciated release 3.0
+ {
+ formatter.setAddOneLineBracketsMode(true);
+ }
+ else if ( isOption(arg, "remove-brackets") ) // depreciated release 3.0
+ {
+ formatter.setRemoveBracketsMode(true);
+ }
+ else if ( isParamOption(arg, "max-instatement-indent=") ) // depreciated release 3.0
+ {
+ int maxIndent = 40;
+ string maxIndentParam = getParam(arg, "max-instatement-indent=");
+ if (maxIndentParam.length() > 0)
+ maxIndent = atoi(maxIndentParam.c_str());
+ if (maxIndent < 40)
+ isOptionError(arg, errorInfo);
+ else if (maxIndent > 120)
+ isOptionError(arg, errorInfo);
+ else
+ formatter.setMaxInStatementIndentLength(maxIndent);
+ }
+// NOTE: Removed in release 2.04.
+// else if ( isOption(arg, "b", "brackets=break") )
+// {
+// formatter.setBracketFormatMode(BREAK_MODE);
+// }
+// else if ( isOption(arg, "a", "brackets=attach") )
+// {
+// formatter.setBracketFormatMode(ATTACH_MODE);
+// }
+// else if ( isOption(arg, "l", "brackets=linux") )
+// {
+// formatter.setBracketFormatMode(LINUX_MODE);
+// }
+// else if ( isOption(arg, "u", "brackets=stroustrup") )
+// {
+// formatter.setBracketFormatMode(STROUSTRUP_MODE);
+// }
+// else if ( isOption(arg, "g", "brackets=run-in") )
+// {
+// formatter.setBracketFormatMode(RUN_IN_MODE);
+// }
+ // end depreciated options ////////////////////////////////////////////////////////////////////
+#ifdef ASTYLE_LIB
+ // End of options used by GUI /////////////////////////////////////////////////////////////////
+ else
+ isOptionError(arg, errorInfo);
+#else
+ // Options used by only console ///////////////////////////////////////////////////////////////
+ else if ( isOption(arg, "n", "suffix=none") )
+ {
+ console.setNoBackup(true);
+ }
+ else if ( isParamOption(arg, "suffix=") )
+ {
+ string suffixParam = getParam(arg, "suffix=");
+ if (suffixParam.length() > 0)
+ {
+ console.setOrigSuffix(suffixParam);
+ }
+ }
+ else if ( isParamOption(arg, "exclude=") )
+ {
+ string suffixParam = getParam(arg, "exclude=");
+ if (suffixParam.length() > 0)
+ console.updateExcludeVector(suffixParam);
+ }
+ else if ( isOption(arg, "r", "R") || isOption(arg, "recursive") )
+ {
+ console.setIsRecursive(true);
+ }
+ else if (isOption(arg, "dry-run"))
+ {
+ console.setIsDryRun(true);
+ }
+ else if ( isOption(arg, "Z", "preserve-date") )
+ {
+ console.setPreserveDate(true);
+ }
+ else if ( isOption(arg, "v", "verbose") )
+ {
+ console.setIsVerbose(true);
+ }
+ else if ( isOption(arg, "Q", "formatted") )
+ {
+ console.setIsFormattedOnly(true);
+ }
+ else if ( isOption(arg, "q", "quiet") )
+ {
+ console.setIsQuiet(true);
+ }
+ else if ( isOption(arg, "i", "ignore-exclude-errors") )
+ {
+ console.setIgnoreExcludeErrors(true);
+ }
+ else if ( isOption(arg, "xi", "ignore-exclude-errors-x") )
+ {
+ console.setIgnoreExcludeErrorsAndDisplay(true);
+ }
+ else if ( isOption(arg, "X", "errors-to-stdout") )
+ {
+ console.setErrorStream(&cout);
+ }
+ else if ( isOption(arg, "lineend=windows") )
+ {
+ formatter.setLineEndFormat(LINEEND_WINDOWS);
+ }
+ else if ( isOption(arg, "lineend=linux") )
+ {
+ formatter.setLineEndFormat(LINEEND_LINUX);
+ }
+ else if ( isOption(arg, "lineend=macold") )
+ {
+ formatter.setLineEndFormat(LINEEND_MACOLD);
+ }
+ else if ( isParamOption(arg, "z") )
+ {
+ int lineendType = 0;
+ string lineendParam = getParam(arg, "z");
+ if (lineendParam.length() > 0)
+ lineendType = atoi(lineendParam.c_str());
+ if (lineendType < 1 || lineendType > 3)
+ isOptionError(arg, errorInfo);
+ else if (lineendType == 1)
+ formatter.setLineEndFormat(LINEEND_WINDOWS);
+ else if (lineendType == 2)
+ formatter.setLineEndFormat(LINEEND_LINUX);
+ else if (lineendType == 3)
+ formatter.setLineEndFormat(LINEEND_MACOLD);
+ }
+ else if ( isParamOption(arg, "stdin=") )
+ {
+ string path = getParam(arg, "stdin=");
+ console.standardizePath(path);
+ console.setStdPathIn(path);
+ }
+ else if ( isParamOption(arg, "stdout=") )
+ {
+ string path = getParam(arg, "stdout=");
+ console.standardizePath(path);
+ console.setStdPathOut(path);
+ }
+ else
+ isOptionError(arg, errorInfo);
+#endif
+} // End of parseOption function
+
+// Parse options from the options file.
+void ASOptions::importOptions(istream& in, vector<string>& optionsVector)
+{
+ char ch;
+ bool isInQuote = false;
+ char quoteChar = ' ';
+ string currentToken;
+
+ while (in)
+ {
+ currentToken = "";
+ do
+ {
+ in.get(ch);
+ if (in.eof())
+ break;
+ // treat '#' as line comments
+ if (ch == '#')
+ while (in)
+ {
+ in.get(ch);
+ if (ch == '\n' || ch == '\r')
+ break;
+ }
+
+ // break options on new-lines, tabs, commas, or spaces
+ // remove quotes from output
+ if (in.eof() || ch == '\n' || ch == '\r' || ch == '\t' || ch == ',')
+ break;
+ if (ch == ' ' && !isInQuote)
+ break;
+ if (ch == quoteChar && isInQuote)
+ break;
+ if (ch == '"' || ch == '\'')
+ {
+ isInQuote = true;
+ quoteChar = ch;
+ continue;
+ }
+ currentToken.append(1, ch);
+ }
+ while (in);
+
+ if (currentToken.length() != 0)
+ optionsVector.emplace_back(currentToken);
+ isInQuote = false;
+ }
+}
+
+string ASOptions::getOptionErrors() const
+{
+ return optionErrors.str();
+}
+
+string ASOptions::getParam(const string& arg, const char* op)
+{
+ return arg.substr(strlen(op));
+}
+
+string ASOptions::getParam(const string& arg, const char* op1, const char* op2)
+{
+ return isParamOption(arg, op1) ? getParam(arg, op1) : getParam(arg, op2);
+}
+
+bool ASOptions::isOption(const string& arg, const char* op)
+{
+ return arg.compare(op) == 0;
+}
+
+bool ASOptions::isOption(const string& arg, const char* op1, const char* op2)
+{
+ return (isOption(arg, op1) || isOption(arg, op2));
+}
+
+void ASOptions::isOptionError(const string& arg, const string& errorInfo)
+{
+ if (optionErrors.str().length() == 0)
+ optionErrors << errorInfo << endl; // need main error message
+ optionErrors << arg << endl;
+}
+
+bool ASOptions::isParamOption(const string& arg, const char* option)
+{
+ bool retVal = arg.compare(0, strlen(option), option) == 0;
+ // if comparing for short option, 2nd char of arg must be numeric
+ if (retVal && strlen(option) == 1 && arg.length() > 1)
+ if (!isdigit((unsigned char)arg[1]))
+ retVal = false;
+ return retVal;
+}
+
+bool ASOptions::isParamOption(const string& arg, const char* option1, const char* option2)
+{
+ return isParamOption(arg, option1) || isParamOption(arg, option2);
+}
+
+//----------------------------------------------------------------------------
+// ASEncoding class
+//----------------------------------------------------------------------------
+
+// Return true if an int is big endian.
+bool ASEncoding::getBigEndian() const
+{
+ short int word = 0x0001;
+ char* byte = (char*) &word;
+ return (byte[0] ? false : true);
+}
+
+// Swap the two low order bytes of a 16 bit integer value.
+int ASEncoding::swap16bit(int value) const
+{
+ return ( ((value & 0xff) << 8) | ((value & 0xff00) >> 8) );
+}
+
+// Return the length of a utf-16 C string.
+// The length is in number of utf16_t.
+size_t ASEncoding::utf16len(const utf16* utf16In) const
+{
+ size_t length = 0;
+ while (*utf16In++ != '\0')
+ length++;
+ return length;
+}
+
+// Adapted from SciTE UniConversion.cxx.
+// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
+// Modified for Artistic Style by Jim Pattee.
+// Compute the length of an output utf-8 file given a utf-16 file.
+// Input inLen is the size in BYTES (not wchar_t).
+size_t ASEncoding::utf8LengthFromUtf16(const char* utf16In, size_t inLen, bool isBigEndian) const
+{
+ size_t len = 0;
+ size_t wcharLen = inLen / 2;
+ const short* uptr = reinterpret_cast<const short*>(utf16In);
+ for (size_t i = 0; i < wcharLen && uptr[i];)
+ {
+ size_t uch = isBigEndian ? swap16bit(uptr[i]) : uptr[i];
+ if (uch < 0x80)
+ len++;
+ else if (uch < 0x800)
+ len += 2;
+ else if ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_TRAIL_LAST))
+ {
+ len += 4;
+ i++;
+ }
+ else
+ len += 3;
+ i++;
+ }
+ return len;
+}
+
+// Adapted from SciTE Utf8_16.cxx.
+// Copyright (C) 2002 Scott Kirkwood.
+// Modified for Artistic Style by Jim Pattee.
+// Convert a utf-8 file to utf-16.
+size_t ASEncoding::utf8ToUtf16(char* utf8In, size_t inLen, bool isBigEndian, char* utf16Out) const
+{
+ int nCur = 0;
+ ubyte* pRead = reinterpret_cast<ubyte*>(utf8In);
+ utf16* pCur = reinterpret_cast<utf16*>(utf16Out);
+ const ubyte* pEnd = pRead + inLen;
+ const utf16* pCurStart = pCur;
+ eState state = eStart;
+
+ // the BOM will automatically be converted to utf-16
+ while (pRead < pEnd)
+ {
+ switch (state)
+ {
+ case eStart:
+ if ((0xF0 & *pRead) == 0xF0)
+ {
+ nCur = (0x7 & *pRead) << 18;
+ state = eSecondOf4Bytes;
+ }
+ else if ((0xE0 & *pRead) == 0xE0)
+ {
+ nCur = (~0xE0 & *pRead) << 12;
+ state = ePenultimate;
+ }
+ else if ((0xC0 & *pRead) == 0xC0)
+ {
+ nCur = (~0xC0 & *pRead) << 6;
+ state = eFinal;
+ }
+ else
+ {
+ nCur = *pRead;
+ state = eStart;
+ }
+ break;
+ case eSecondOf4Bytes:
+ nCur |= (0x3F & *pRead) << 12;
+ state = ePenultimate;
+ break;
+ case ePenultimate:
+ nCur |= (0x3F & *pRead) << 6;
+ state = eFinal;
+ break;
+ case eFinal:
+ nCur |= (0x3F & *pRead);
+ state = eStart;
+ break;
+ // no default case is needed
+ }
+ ++pRead;
+
+ if (state == eStart)
+ {
+ int codePoint = nCur;
+ if (codePoint >= SURROGATE_FIRST_VALUE)
+ {
+ codePoint -= SURROGATE_FIRST_VALUE;
+ int lead = (codePoint >> 10) + SURROGATE_LEAD_FIRST;
+ *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(lead) : lead);
+ int trail = (codePoint & 0x3ff) + SURROGATE_TRAIL_FIRST;
+ *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(trail) : trail);
+ }
+ else
+ *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(codePoint) : codePoint);
+ }
+ }
+ // return value is the output length in BYTES (not wchar_t)
+ return (pCur - pCurStart) * 2;
+}
+
+// Adapted from SciTE UniConversion.cxx.
+// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
+// Modified for Artistic Style by Jim Pattee.
+// Compute the length of an output utf-16 file given a utf-8 file.
+// Return value is the size in BYTES (not wchar_t).
+size_t ASEncoding::utf16LengthFromUtf8(const char* utf8In, size_t len) const
+{
+ size_t ulen = 0;
+ size_t charLen;
+ for (size_t i = 0; i < len;)
+ {
+ unsigned char ch = static_cast<unsigned char>(utf8In[i]);
+ if (ch < 0x80)
+ charLen = 1;
+ else if (ch < 0x80 + 0x40 + 0x20)
+ charLen = 2;
+ else if (ch < 0x80 + 0x40 + 0x20 + 0x10)
+ charLen = 3;
+ else
+ {
+ charLen = 4;
+ ulen++;
+ }
+ i += charLen;
+ ulen++;
+ }
+ // return value is the length in bytes (not wchar_t)
+ return ulen * 2;
+}
+
+// Adapted from SciTE Utf8_16.cxx.
+// Copyright (C) 2002 Scott Kirkwood.
+// Modified for Artistic Style by Jim Pattee.
+// Convert a utf-16 file to utf-8.
+size_t ASEncoding::utf16ToUtf8(char* utf16In, size_t inLen, bool isBigEndian,
+ bool firstBlock, char* utf8Out) const
+{
+ int nCur16 = 0;
+ int nCur = 0;
+ ubyte* pRead = reinterpret_cast<ubyte*>(utf16In);
+ ubyte* pCur = reinterpret_cast<ubyte*>(utf8Out);
+ const ubyte* pEnd = pRead + inLen;
+ const ubyte* pCurStart = pCur;
+ static eState state = eStart; // state is retained for subsequent blocks
+ if (firstBlock)
+ state = eStart;
+
+ // the BOM will automatically be converted to utf-8
+ while (pRead < pEnd)
+ {
+ switch (state)
+ {
+ case eStart:
+ if (pRead >= pEnd)
+ {
+ ++pRead;
+ break;
+ }
+ if (isBigEndian)
+ {
+ nCur16 = static_cast<utf16>(*pRead++ << 8);
+ nCur16 |= static_cast<utf16>(*pRead);
+ }
+ else
+ {
+ nCur16 = *pRead++;
+ nCur16 |= static_cast<utf16>(*pRead << 8);
+ }
+ if (nCur16 >= SURROGATE_LEAD_FIRST && nCur16 <= SURROGATE_LEAD_LAST)
+ {
+ ++pRead;
+ int trail;
+ if (isBigEndian)
+ {
+ trail = static_cast<utf16>(*pRead++ << 8);
+ trail |= static_cast<utf16>(*pRead);
+ }
+ else
+ {
+ trail = *pRead++;
+ trail |= static_cast<utf16>(*pRead << 8);
+ }
+ nCur16 = (((nCur16 & 0x3ff) << 10) | (trail & 0x3ff)) + SURROGATE_FIRST_VALUE;
+ }
+ ++pRead;
+
+ if (nCur16 < 0x80)
+ {
+ nCur = static_cast<ubyte>(nCur16 & 0xFF);
+ state = eStart;
+ }
+ else if (nCur16 < 0x800)
+ {
+ nCur = static_cast<ubyte>(0xC0 | (nCur16 >> 6));
+ state = eFinal;
+ }
+ else if (nCur16 < SURROGATE_FIRST_VALUE)
+ {
+ nCur = static_cast<ubyte>(0xE0 | (nCur16 >> 12));
+ state = ePenultimate;
+ }
+ else
+ {
+ nCur = static_cast<ubyte>(0xF0 | (nCur16 >> 18));
+ state = eSecondOf4Bytes;
+ }
+ break;
+ case eSecondOf4Bytes:
+ nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 12) & 0x3F));
+ state = ePenultimate;
+ break;
+ case ePenultimate:
+ nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 6) & 0x3F));
+ state = eFinal;
+ break;
+ case eFinal:
+ nCur = static_cast<ubyte>(0x80 | (nCur16 & 0x3F));
+ state = eStart;
+ break;
+ // no default case is needed
+ }
+ *pCur++ = static_cast<ubyte>(nCur);
+ }
+ return pCur - pCurStart;
+}
+
+//----------------------------------------------------------------------------
+
+} // namespace astyle
+
+//----------------------------------------------------------------------------
+
+using namespace astyle;
+
+//----------------------------------------------------------------------------
+// ASTYLE_JNI functions for Java library builds
+//----------------------------------------------------------------------------
+
+#ifdef ASTYLE_JNI
+
+// called by a java program to get the version number
+// the function name is constructed from method names in the calling java program
+extern "C" EXPORT
+jstring STDCALL Java_AStyleInterface_AStyleGetVersion(JNIEnv* env, jclass)
+{
+ return env->NewStringUTF(g_version);
+}
+
+// called by a java program to format the source code
+// the function name is constructed from method names in the calling java program
+extern "C" EXPORT
+jstring STDCALL Java_AStyleInterface_AStyleMain(JNIEnv* env,
+ jobject obj,
+ jstring textInJava,
+ jstring optionsJava)
+{
+ g_env = env; // make object available globally
+ g_obj = obj; // make object available globally
+
+ jstring textErr = env->NewStringUTF(""); // zero length text returned if an error occurs
+
+ // get the method ID
+ jclass cls = env->GetObjectClass(obj);
+ g_mid = env->GetMethodID(cls, "ErrorHandler", "(ILjava/lang/String;)V");
+ if (g_mid == nullptr)
+ {
+ cout << "Cannot find java method ErrorHandler" << endl;
+ return textErr;
+ }
+
+ // convert jstring to char*
+ const char* textIn = env->GetStringUTFChars(textInJava, nullptr);
+ const char* options = env->GetStringUTFChars(optionsJava, nullptr);
+
+ // call the C++ formatting function
+ char* textOut = AStyleMain(textIn, options, javaErrorHandler, javaMemoryAlloc);
+ // if an error message occurred it was displayed by errorHandler
+ if (textOut == nullptr)
+ return textErr;
+
+ // release memory
+ jstring textOutJava = env->NewStringUTF(textOut);
+ delete[] textOut;
+ env->ReleaseStringUTFChars(textInJava, textIn);
+ env->ReleaseStringUTFChars(optionsJava, options);
+
+ return textOutJava;
+}
+
+// Call the Java error handler
+void STDCALL javaErrorHandler(int errorNumber, const char* errorMessage)
+{
+ jstring errorMessageJava = g_env->NewStringUTF(errorMessage);
+ g_env->CallVoidMethod(g_obj, g_mid, errorNumber, errorMessageJava);
+}
+
+// Allocate memory for the formatted text
+char* STDCALL javaMemoryAlloc(unsigned long memoryNeeded)
+{
+ // error condition is checked after return from AStyleMain
+ char* buffer = new (nothrow) char[memoryNeeded];
+ return buffer;
+}
+
+#endif // ASTYLE_JNI
+
+//----------------------------------------------------------------------------
+// ASTYLE_LIB functions for library builds
+//----------------------------------------------------------------------------
+
+#ifdef ASTYLE_LIB
+
+//----------------------------------------------------------------------------
+// ASTYLE_LIB entry point for AStyleMainUtf16 library builds
+//----------------------------------------------------------------------------
+/*
+* IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
+* /EXPORT:AStyleMain=_AStyleMain@16
+* /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
+* /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
+* No /EXPORT is required for x64
+*/
+extern "C" EXPORT utf16_t* STDCALL AStyleMainUtf16(const utf16_t* pSourceIn, // the source to be formatted
+ const utf16_t* pOptions, // AStyle options
+ fpError fpErrorHandler, // error handler function
+ fpAlloc fpMemoryAlloc) // memory allocation function
+{
+ if (fpErrorHandler == nullptr) // cannot display a message if no error handler
+ return nullptr;
+
+ if (pSourceIn == nullptr)
+ {
+ fpErrorHandler(101, "No pointer to source input.");
+ return nullptr;
+ }
+ if (pOptions == nullptr)
+ {
+ fpErrorHandler(102, "No pointer to AStyle options.");
+ return nullptr;
+ }
+ if (fpMemoryAlloc == nullptr)
+ {
+ fpErrorHandler(103, "No pointer to memory allocation function.");
+ return nullptr;
+ }
+#ifndef _WIN32
+ // check size of utf16_t on Linux
+ int sizeCheck = 2;
+ if (sizeof(utf16_t) != sizeCheck)
+ {
+ fpErrorHandler(104, "Unsigned short is not the correct size.");
+ return nullptr;
+ }
+#endif
+
+ ASLibrary library;
+ utf16_t* utf16Out = library.formatUtf16(pSourceIn, pOptions, fpErrorHandler, fpMemoryAlloc);
+ return utf16Out;
+}
+
+//----------------------------------------------------------------------------
+// ASTYLE_LIB entry point for library builds
+//----------------------------------------------------------------------------
+/*
+ * IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
+ * /EXPORT:AStyleMain=_AStyleMain@16
+ * /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
+ * /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
+ * No /EXPORT is required for x64
+ */
+extern "C" EXPORT char* STDCALL AStyleMain(const char* pSourceIn, // the source to be formatted
+ const char* pOptions, // AStyle options
+ fpError fpErrorHandler, // error handler function
+ fpAlloc fpMemoryAlloc) // memory allocation function
+{
+ if (fpErrorHandler == nullptr) // cannot display a message if no error handler
+ return nullptr;
+
+ if (pSourceIn == nullptr)
+ {
+ fpErrorHandler(101, "No pointer to source input.");
+ return nullptr;
+ }
+ if (pOptions == nullptr)
+ {
+ fpErrorHandler(102, "No pointer to AStyle options.");
+ return nullptr;
+ }
+ if (fpMemoryAlloc == nullptr)
+ {
+ fpErrorHandler(103, "No pointer to memory allocation function.");
+ return nullptr;
+ }
+
+ ASFormatter formatter;
+ ASOptions options(formatter);
+
+ vector<string> optionsVector;
+ istringstream opt(pOptions);
+
+ options.importOptions(opt, optionsVector);
+
+ bool ok = options.parseOptions(optionsVector, "Invalid Artistic Style options:");
+ if (!ok)
+ fpErrorHandler(130, options.getOptionErrors().c_str());
+
+ istringstream in(pSourceIn);
+ ASStreamIterator<istringstream> streamIterator(&in);
+ ostringstream out;
+ formatter.init(&streamIterator);
+
+ while (formatter.hasMoreLines())
+ {
+ out << formatter.nextLine();
+ if (formatter.hasMoreLines())
+ out << streamIterator.getOutputEOL();
+ else
+ {
+ // this can happen if the file if missing a closing brace and break-blocks is requested
+ if (formatter.getIsLineReady())
+ {
+ out << streamIterator.getOutputEOL();
+ out << formatter.nextLine();
+ }
+ }
+ }
+
+ size_t textSizeOut = out.str().length();
+ char* pTextOut = fpMemoryAlloc((long)textSizeOut + 1); // call memory allocation function
+ if (pTextOut == nullptr)
+ {
+ fpErrorHandler(120, "Allocation failure on output.");
+ return nullptr;
+ }
+
+ strcpy(pTextOut, out.str().c_str());
+#ifndef NDEBUG
+ // The checksum is an assert in the console build and ASFormatter.
+ // This error returns the incorrectly formatted file to the editor.
+ // This is done to allow the file to be saved for debugging purposes.
+ if (formatter.getChecksumDiff() != 0)
+ fpErrorHandler(220,
+ "Checksum error.\n"
+ "The incorrectly formatted file will be returned for debugging.");
+#endif
+ return pTextOut;
+}
+
+extern "C" EXPORT const char* STDCALL AStyleGetVersion(void)
+{
+ return g_version;
+}
+
+// ASTYLECON_LIB is defined to exclude "main" from the test programs
+#elif !defined(ASTYLECON_LIB)
+
+//----------------------------------------------------------------------------
+// main function for ASConsole build
+//----------------------------------------------------------------------------
+
+int main(int argc, char** argv)
+{
+ // create objects
+ ASFormatter formatter;
+ auto console = make_shared<ASConsole>(formatter);
+
+ // process command line and options file
+ // build the vectors fileNameVector, optionsVector, and fileOptionsVector
+ vector<string> argvOptions;
+ argvOptions = console->getArgvOptions(argc, argv);
+ console->processOptions(argvOptions);
+
+ // if no files have been given, use cin for input and cout for output
+ if (!console->fileNameVectorIsEmpty())
+ console->processFiles();
+ else
+ console->formatCinToCout();
+
+ return EXIT_SUCCESS;
+}
+
+#endif // ASTYLE_LIB
--- /dev/null
+// astyle_main.h
+// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
+// This code is licensed under the MIT License.
+// License.md describes the conditions under which this software may be distributed.
+
+#ifndef ASTYLE_MAIN_H
+#define ASTYLE_MAIN_H
+
+//----------------------------------------------------------------------------
+// headers
+//----------------------------------------------------------------------------
+
+#include "astyle.h"
+
+#include <sstream>
+#include <ctime>
+
+#if defined(__BORLANDC__) && __BORLANDC__ < 0x0650
+ // Embarcadero needs this for the following utime.h
+ // otherwise "struct utimbuf" gets an error on time_t
+ // 0x0650 for C++Builder XE3
+ using std::time_t;
+#endif
+
+#if defined(_MSC_VER)
+ #include <sys/utime.h>
+ #include <sys/stat.h>
+#else
+ #include <utime.h>
+ #include <sys/stat.h>
+#endif // end compiler checks
+
+#ifdef ASTYLE_JNI
+ #include <jni.h>
+ #ifndef ASTYLE_LIB // ASTYLE_LIB must be defined for ASTYLE_JNI
+ #define ASTYLE_LIB
+ #endif
+#endif // ASTYLE_JNI
+
+#ifndef ASTYLE_LIB
+ // for console build only
+ #include "ASLocalizer.h"
+ #define _(a) localizer.settext(a)
+#endif // ASTYLE_LIB
+
+//-----------------------------------------------------------------------------
+// declarations
+//-----------------------------------------------------------------------------
+
+// for G++ implementation of string.compare:
+#if defined(__GNUC__) && __GNUC__ < 3
+ #error - Use GNU C compiler release 3 or higher
+#endif
+
+// for getenv and localtime
+#if defined(_MSC_VER)
+ #pragma warning(disable: 4996) // secure version deprecation warnings
+#endif
+
+// for namespace problem in version 5.0
+#if defined(_MSC_VER) && _MSC_VER < 1200 // check for V6.0
+ #error - Use Microsoft compiler version 6 or higher
+#endif
+
+#ifdef __clang__
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations" // getenv, localtime
+ #pragma clang diagnostic ignored "-Wmissing-braces"
+#endif
+
+// for mingw BOM, UTF-16, and Unicode functions
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+ #if (__MINGW32_MAJOR_VERSION > 3) || \
+ ((__MINGW32_MAJOR_VERSION == 3) && (__MINGW32_MINOR_VERSION < 16))
+ #error - Use MinGW compiler version 4 or higher
+ #endif
+#endif
+
+#ifdef ASTYLE_LIB
+
+ // define STDCALL and EXPORT for Windows
+ // MINGW defines STDCALL in Windows.h (actually windef.h)
+ // EXPORT has no value if ASTYLE_NO_EXPORT is defined
+ #ifdef _WIN32
+ #ifndef STDCALL
+ #define STDCALL __stdcall
+ #endif
+ // define this to prevent compiler warning and error messages
+ #ifdef ASTYLE_NO_EXPORT
+ #define EXPORT
+ #else
+ #define EXPORT __declspec(dllexport)
+ #endif
+ // define STDCALL and EXPORT for non-Windows
+ // visibility attribute allows "-fvisibility=hidden" compiler option
+ #else
+ #define STDCALL
+ #if __GNUC__ >= 4
+ #define EXPORT __attribute__ ((visibility ("default")))
+ #else
+ #define EXPORT
+ #endif
+ #endif // #ifdef _WIN32
+
+ // define utf-16 bit text for the platform
+ typedef unsigned short utf16_t;
+ // define pointers to callback error handler and memory allocation
+ typedef void (STDCALL* fpError)(int errorNumber, const char* errorMessage);
+ typedef char* (STDCALL* fpAlloc)(unsigned long memoryNeeded);
+
+#endif // #ifdef ASTYLE_LIB
+
+//----------------------------------------------------------------------------
+// astyle namespace
+//----------------------------------------------------------------------------
+
+namespace astyle {
+//
+//----------------------------------------------------------------------------
+// ASStreamIterator class
+// typename will be istringstream for GUI and istream otherwise
+// ASSourceIterator is an abstract class defined in astyle.h
+//----------------------------------------------------------------------------
+
+template<typename T>
+class ASStreamIterator : public ASSourceIterator
+{
+public:
+ bool checkForEmptyLine;
+
+ // function declarations
+ explicit ASStreamIterator(T* in);
+ virtual ~ASStreamIterator();
+ bool getLineEndChange(int lineEndFormat) const;
+ int getStreamLength() const;
+ string nextLine(bool emptyLineWasDeleted);
+ string peekNextLine();
+ void peekReset();
+ void saveLastInputLine();
+ streamoff tellg();
+
+private:
+ ASStreamIterator(const ASStreamIterator& copy); // copy constructor not to be implemented
+ ASStreamIterator& operator=(ASStreamIterator&); // assignment operator not to be implemented
+ T* inStream; // pointer to the input stream
+ string buffer; // current input line
+ string prevBuffer; // previous input line
+ string outputEOL; // next output end of line char
+ int eolWindows; // number of Windows line endings, CRLF
+ int eolLinux; // number of Linux line endings, LF
+ int eolMacOld; // number of old Mac line endings. CR
+ streamoff streamLength; // length of the input file stream
+ streamoff peekStart; // starting position for peekNextLine
+ bool prevLineDeleted; // the previous input line was deleted
+
+public: // inline functions
+ bool compareToInputBuffer(const string& nextLine_) const
+ { return (nextLine_ == prevBuffer); }
+ const string& getOutputEOL() const { return outputEOL; }
+ bool hasMoreLines() const { return !inStream->eof(); }
+};
+
+//----------------------------------------------------------------------------
+// ASEncoding class for utf8/16 conversions
+// used by both console and library builds
+//----------------------------------------------------------------------------
+
+class ASEncoding
+{
+private:
+ typedef unsigned short utf16; // 16 bits
+ typedef unsigned char utf8; // 8 bits
+ typedef unsigned char ubyte; // 8 bits
+ enum { SURROGATE_LEAD_FIRST = 0xD800 };
+ enum { SURROGATE_LEAD_LAST = 0xDBFF };
+ enum { SURROGATE_TRAIL_FIRST = 0xDC00 };
+ enum { SURROGATE_TRAIL_LAST = 0xDFFF };
+ enum { SURROGATE_FIRST_VALUE = 0x10000 };
+ enum eState { eStart, eSecondOf4Bytes, ePenultimate, eFinal };
+
+public:
+ bool getBigEndian() const;
+ int swap16bit(int value) const;
+ size_t utf16len(const utf16* utf16In) const;
+ size_t utf8LengthFromUtf16(const char* utf16In, size_t inLen, bool isBigEndian) const;
+ size_t utf8ToUtf16(char* utf8In, size_t inLen, bool isBigEndian, char* utf16Out) const;
+ size_t utf16LengthFromUtf8(const char* utf8In, size_t len) const;
+ size_t utf16ToUtf8(char* utf16In, size_t inLen, bool isBigEndian,
+ bool firstBlock, char* utf8Out) const;
+};
+
+//----------------------------------------------------------------------------
+// ASOptions class for options processing
+// used by both console and library builds
+//----------------------------------------------------------------------------
+class ASConsole;
+
+class ASOptions
+{
+public:
+#ifdef ASTYLE_LIB
+ ASOptions(ASFormatter& formatterArg);
+#else
+ ASOptions(ASFormatter& formatterArg, ASConsole& consoleArg);
+#endif
+ string getOptionErrors() const;
+ void importOptions(istream& in, vector<string>& optionsVector);
+ bool parseOptions(vector<string>& optionsVector, const string& errorInfo);
+
+private:
+ // variables
+ ASFormatter& formatter;
+ stringstream optionErrors; // option error messages
+#ifndef ASTYLE_LIB
+ ASConsole& console; // DO NOT USE for ASTYLE_LIB
+#endif
+
+ // functions
+ ASOptions(const ASOptions&); // copy constructor not to be implemented
+ ASOptions& operator=(ASOptions&); // assignment operator not to be implemented
+ string getParam(const string& arg, const char* op);
+ string getParam(const string& arg, const char* op1, const char* op2);
+ bool isOption(const string& arg, const char* op);
+ bool isOption(const string& arg, const char* op1, const char* op2);
+ void isOptionError(const string& arg, const string& errorInfo);
+ bool isParamOption(const string& arg, const char* option);
+ bool isParamOption(const string& arg, const char* option1, const char* option2);
+ void parseOption(const string& arg, const string& errorInfo);
+};
+
+#ifndef ASTYLE_LIB
+
+//----------------------------------------------------------------------------
+// ASConsole class for console build
+//----------------------------------------------------------------------------
+
+class ASConsole
+{
+private: // variables
+ ASFormatter& formatter; // reference to the ASFormatter object
+ ASLocalizer localizer; // ASLocalizer object
+ ostream* errorStream; // direct error messages to cerr or cout
+ // command line options
+ bool isRecursive; // recursive option
+ bool isDryRun; // dry-run option
+ bool noBackup; // suffix=none option
+ bool preserveDate; // preserve-date option
+ bool isVerbose; // verbose option
+ bool isQuiet; // quiet option
+ bool isFormattedOnly; // formatted lines only option
+ bool ignoreExcludeErrors; // don't abort on unmatched excludes
+ bool ignoreExcludeErrorsDisplay; // don't display unmatched excludes
+ bool optionsFileRequired; // options= option
+ bool useAscii; // ascii option
+ // other variables
+ bool bypassBrowserOpen; // don't open the browser on html options
+ bool hasWildcard; // file name includes a wildcard
+ size_t mainDirectoryLength; // directory length to be excluded in displays
+ bool filesAreIdentical; // input and output files are identical
+ int filesFormatted; // number of files formatted
+ int filesUnchanged; // number of files unchanged
+ bool lineEndsMixed; // output has mixed line ends
+ int linesOut; // number of output lines
+
+ ASEncoding utf8_16; // utf8/16 conversion methods
+
+ string outputEOL; // current line end
+ string prevEOL; // previous line end
+ string optionsFileName; // file path and name of the options file to use
+ string origSuffix; // suffix= option
+ string stdPathIn; // path to input from stdin=
+ string stdPathOut; // path to output from stdout=
+ string targetDirectory; // path to the directory being processed
+ string targetFilename; // file name being processed
+
+ vector<string> excludeVector; // exclude from wildcard hits
+ vector<bool> excludeHitsVector; // exclude flags for error reporting
+ vector<string> fileNameVector; // file paths and names from the command line
+ vector<string> optionsVector; // options from the command line
+ vector<string> fileOptionsVector; // options from the options file
+ vector<string> fileName; // files to be processed including path
+
+public: // functions
+ explicit ASConsole(ASFormatter& formatterArg);
+ ~ASConsole();
+ void convertLineEnds(ostringstream& out, int lineEnd);
+ FileEncoding detectEncoding(const char* data, size_t dataSize) const;
+ void error() const;
+ void error(const char* why, const char* what) const;
+ void formatCinToCout();
+ vector<string> getArgvOptions(int argc, char** argv) const;
+ bool fileNameVectorIsEmpty() const;
+ ostream* getErrorStream() const;
+ bool getFilesAreIdentical() const;
+ int getFilesFormatted() const;
+ bool getIgnoreExcludeErrors() const;
+ bool getIgnoreExcludeErrorsDisplay() const;
+ bool getIsDryRun() const;
+ bool getIsFormattedOnly() const;
+ bool getIsQuiet() const;
+ bool getIsRecursive() const;
+ bool getIsVerbose() const;
+ bool getLineEndsMixed() const;
+ bool getNoBackup() const;
+ bool getPreserveDate() const;
+ string getLanguageID() const;
+ string getNumberFormat(int num, size_t lcid = 0) const;
+ string getNumberFormat(int num, const char* groupingArg, const char* separator) const;
+ string getOptionsFileName() const;
+ string getOrigSuffix() const;
+ string getStdPathIn() const;
+ string getStdPathOut() const;
+ void processFiles();
+ void processOptions(const vector<string>& argvOptions);
+ void setBypassBrowserOpen(bool state);
+ void setErrorStream(ostream* errStreamPtr);
+ void setIgnoreExcludeErrors(bool state);
+ void setIgnoreExcludeErrorsAndDisplay(bool state);
+ void setIsDryRun(bool state);
+ void setIsFormattedOnly(bool state);
+ void setIsQuiet(bool state);
+ void setIsRecursive(bool state);
+ void setIsVerbose(bool state);
+ void setNoBackup(bool state);
+ void setOptionsFileName(const string& name);
+ void setOrigSuffix(const string& suffix);
+ void setPreserveDate(bool state);
+ void setStdPathIn(const string& path);
+ void setStdPathOut(const string& path);
+ void standardizePath(string& path, bool removeBeginningSeparator = false) const;
+ bool stringEndsWith(const string& str, const string& suffix) const;
+ void updateExcludeVector(const string& suffixParam);
+ vector<string> getExcludeVector() const;
+ vector<bool> getExcludeHitsVector() const;
+ vector<string> getFileNameVector() const;
+ vector<string> getOptionsVector() const;
+ vector<string> getFileOptionsVector() const;
+ vector<string> getFileName() const;
+
+private: // functions
+ ASConsole(const ASConsole&); // copy constructor not to be implemented
+ ASConsole& operator=(ASConsole&); // assignment operator not to be implemented
+ void correctMixedLineEnds(ostringstream& out);
+ void formatFile(const string& fileName_);
+ string getCurrentDirectory(const string& fileName_) const;
+ void getFileNames(const string& directory, const string& wildcard);
+ void getFilePaths(const string& filePath);
+ string getParam(const string& arg, const char* op);
+ void initializeOutputEOL(LineEndFormat lineEndFormat);
+ bool isOption(const string& arg, const char* op);
+ bool isOption(const string& arg, const char* a, const char* b);
+ bool isParamOption(const string& arg, const char* option);
+ bool isPathExclued(const string& subPath);
+ void launchDefaultBrowser(const char* filePathIn = nullptr) const;
+ void printHelp() const;
+ void printMsg(const char* msg, const string& data) const;
+ void printSeparatingLine() const;
+ void printVerboseHeader() const;
+ void printVerboseStats(clock_t startTime) const;
+ FileEncoding readFile(const string& fileName_, stringstream& in) const;
+ void removeFile(const char* fileName_, const char* errMsg) const;
+ void renameFile(const char* oldFileName, const char* newFileName, const char* errMsg) const;
+ void setOutputEOL(LineEndFormat lineEndFormat, const string& currentEOL);
+ void sleep(int seconds) const;
+ int waitForRemove(const char* newFileName) const;
+ int wildcmp(const char* wild, const char* data) const;
+ void writeFile(const string& fileName_, FileEncoding encoding, ostringstream& out) const;
+#ifdef _WIN32
+ void displayLastError();
+#endif
+};
+#else // ASTYLE_LIB
+
+//----------------------------------------------------------------------------
+// ASLibrary class for library build
+//----------------------------------------------------------------------------
+
+class ASLibrary
+{
+public:
+ ASLibrary() {}
+ virtual ~ASLibrary() {}
+ // virtual functions are mocked in testing
+ utf16_t* formatUtf16(const utf16_t*, const utf16_t*, fpError, fpAlloc) const;
+ virtual utf16_t* convertUtf8ToUtf16(const char* utf8In, fpAlloc fpMemoryAlloc) const;
+ virtual char* convertUtf16ToUtf8(const utf16_t* utf16In) const;
+
+private:
+ static char* STDCALL tempMemoryAllocation(unsigned long memoryNeeded);
+
+private:
+ ASEncoding utf8_16; // utf8/16 conversion methods
+};
+
+#endif // ASTYLE_LIB
+
+//----------------------------------------------------------------------------
+
+} // end of namespace astyle
+
+//----------------------------------------------------------------------------
+// declarations for java native interface (JNI) build
+// they are called externally and are NOT part of the namespace
+//----------------------------------------------------------------------------
+#ifdef ASTYLE_JNI
+void STDCALL javaErrorHandler(int errorNumber, const char* errorMessage);
+char* STDCALL javaMemoryAlloc(unsigned long memoryNeeded);
+// the following function names are constructed from method names in the calling java program
+extern "C" EXPORT
+jstring STDCALL Java_AStyleInterface_AStyleGetVersion(JNIEnv* env, jclass);
+extern "C" EXPORT
+jstring STDCALL Java_AStyleInterface_AStyleMain(JNIEnv* env,
+ jobject obj,
+ jstring textInJava,
+ jstring optionsJava);
+#endif // ASTYLE_JNI
+
+//----------------------------------------------------------------------------
+// declarations for UTF-16 interface
+// they are called externally and are NOT part of the namespace
+//----------------------------------------------------------------------------
+#ifdef ASTYLE_LIB
+extern "C" EXPORT
+utf16_t* STDCALL AStyleMainUtf16(const utf16_t* pSourceIn,
+ const utf16_t* pOptions,
+ fpError fpErrorHandler,
+ fpAlloc fpMemoryAlloc);
+#endif // ASTYLE_LIB
+
+//-----------------------------------------------------------------------------
+// declarations for standard DLL interface
+// they are called externally and are NOT part of the namespace
+//-----------------------------------------------------------------------------
+#ifdef ASTYLE_LIB
+extern "C" EXPORT char* STDCALL AStyleMain(const char* pSourceIn,
+ const char* pOptions,
+ fpError fpErrorHandler,
+ fpAlloc fpMemoryAlloc);
+extern "C" EXPORT const char* STDCALL AStyleGetVersion(void);
+#endif // ASTYLE_LIB
+
+//-----------------------------------------------------------------------------
+
+#endif // closes ASTYLE_MAIN_H
set(BUILD_TESTING "FALSE")
endif(NOT "$ENV{OPJ_CI_SKIP_TESTS}" STREQUAL "1")
+
+if("$ENV{OPJ_CI_CHECK_STYLE}" STREQUAL "1")
+ set(BUILD_ASTYLE "TRUE")
+else()
+ set(BUILD_ASTYLE "FALSE")
+endif("$ENV{OPJ_CI_CHECK_STYLE}" STREQUAL "1")
+
# Options
set( CACHE_CONTENTS "
# Warning level
CMAKE_C_FLAGS:STRING= ${CCFLAGS_ARCH} ${CCFLAGS_WARNING}
+# For astyle
+CMAKE_CXX_FLAGS:STRING= ${CCFLAGS_ARCH}
+
# Use to activate the test suite
BUILD_TESTING:BOOL=${BUILD_TESTING}
# jpylyzer is available with on GitHub: https://github.com/openpreserve/jpylyzer
JPYLYZER_EXECUTABLE=$ENV{PWD}/jpylyzer/jpylyzer.${JPYLYZER_EXT}
+# Enable astyle
+WITH_ASTYLE:BOOL=${BUILD_ASTYLE}
" )
#---------------------
fi
fi
fi
+
+if [ "${OPJ_CI_CHECK_STYLE:-}" == "1" ]; then
+ pip install --user autopep8
+fi
exit 0
fi
+if [ "${OPJ_CI_CC:-}" != "" ]; then
+ export CC=${OPJ_CI_CC}
+ echo "Using ${CC}"
+fi
+
+if [ "${OPJ_CI_CXX:-}" != "" ]; then
+ export CXX=${OPJ_CI_CXX}
+ echo "Using ${CXX}"
+fi
+
# Set-up some variables
if [ "${OPJ_CI_BUILD_CONFIGURATION:-}" == "" ]; then
export OPJ_CI_BUILD_CONFIGURATION=Release #default
# ignore ctest exit code & parse this ourselves
set +x
+
+
+if [ "${OPJ_CI_CHECK_STYLE:-}" == "1" ]; then
+ export OPJSTYLE=${PWD}/scripts/opjstyle
+ export PATH=${HOME}/.local/bin:${PATH}
+ scripts/verify-indentation.sh
+fi
+
+
# Deployment if needed
#---------------------
if [ "${TRAVIS_TAG:-}" != "" ]; then