summaryrefslogtreecommitdiff
path: root/thirdparty/astyle/astyle_main.cpp
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2017-05-09 15:28:09 +0200
committerEven Rouault <even.rouault@spatialys.com>2017-05-09 20:46:16 +0200
commitd4e54e9f35d532062533f1d369c159810b01d224 (patch)
tree7046ff72a41a8b0ad2e40e1d4aa3b191d03f6380 /thirdparty/astyle/astyle_main.cpp
parent8650b70e06408d394c1708846b6fc2d86cf14079 (diff)
Add mechanisms to reformant and check code style (#128)
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.
Diffstat (limited to 'thirdparty/astyle/astyle_main.cpp')
-rwxr-xr-xthirdparty/astyle/astyle_main.cpp3990
1 files changed, 3990 insertions, 0 deletions
diff --git a/thirdparty/astyle/astyle_main.cpp b/thirdparty/astyle/astyle_main.cpp
new file mode 100755
index 00000000..e9d5c1a0
--- /dev/null
+++ b/thirdparty/astyle/astyle_main.cpp
@@ -0,0 +1,3990 @@
+// 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(&lt);
+ 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