4360 lines
126 KiB
C++
4360 lines
126 KiB
C++
|
// astyle_main.cpp
|
||
|
// Copyright (c) 2018 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 <sys/stat.h>
|
||
|
#include <unistd.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.2 beta";
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
// ASStreamIterator class
|
||
|
// typename will be stringstream for AStyle
|
||
|
// it could be istream or wxChar for plug-ins
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
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() = default;
|
||
|
|
||
|
/**
|
||
|
* 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();
|
||
|
}
|
||
|
|
||
|
// has not detected an input end of line
|
||
|
if (!eolWindows && !eolLinux && !eolMacOld)
|
||
|
{
|
||
|
#ifdef _WIN32
|
||
|
eolWindows++;
|
||
|
#else
|
||
|
eolLinux++;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// 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)
|
||
|
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;
|
||
|
useAscii = false;
|
||
|
// other variables
|
||
|
bypassBrowserOpen = false;
|
||
|
hasWildcard = false;
|
||
|
filesAreIdentical = true;
|
||
|
lineEndsMixed = false;
|
||
|
origSuffix = ".orig";
|
||
|
mainDirectoryLength = 0;
|
||
|
filesFormatted = 0;
|
||
|
filesUnchanged = 0;
|
||
|
linesOut = 0;
|
||
|
}
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
if (lineEnd == LINEEND_LF)
|
||
|
{
|
||
|
outStr += inStr[pos + 1]; // Delete the CR
|
||
|
pos++;
|
||
|
continue;
|
||
|
}
|
||
|
outStr += inStr[pos]; // Do not change
|
||
|
outStr += inStr[pos + 1];
|
||
|
pos++;
|
||
|
continue;
|
||
|
}
|
||
|
else // NOLINT
|
||
|
{
|
||
|
// CR
|
||
|
if (lineEnd == LINEEND_CRLF)
|
||
|
{
|
||
|
outStr += inStr[pos]; // Insert the CR
|
||
|
outStr += '\n'; // Insert the LF
|
||
|
continue;
|
||
|
}
|
||
|
if (lineEnd == LINEEND_LF)
|
||
|
{
|
||
|
outStr += '\n'; // Insert the LF
|
||
|
continue;
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
if (lineEnd == LINEEND_CR)
|
||
|
{
|
||
|
outStr += '\r'; // Insert the CR
|
||
|
continue;
|
||
|
}
|
||
|
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 >= 3 && memcmp(data, "\xEF\xBB\xBF", 3) == 0)
|
||
|
encoding = UTF_8BOM;
|
||
|
else 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) << _("Artistic Style has terminated\n") << 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.
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Searches for a file named fileName_ in the current directory. If it is not
|
||
|
* found, recursively searches for fileName_ in the current directory's parent
|
||
|
* directories, returning the location of the first instance of fileName_
|
||
|
* found. If fileName_ is not found, an empty string is returned.
|
||
|
*
|
||
|
* @param fileName_ The filename the function should attempt to locate.
|
||
|
* @return The full path to fileName_ in the current directory or
|
||
|
* nearest parent directory if found, otherwise an empty
|
||
|
* string.
|
||
|
*/
|
||
|
string ASConsole::findProjectOptionFilePath(const string& fileName_) const
|
||
|
{
|
||
|
string parent;
|
||
|
|
||
|
if (!fileNameVector.empty())
|
||
|
parent = getFullPathName(fileNameVector.front());
|
||
|
else if (!stdPathIn.empty())
|
||
|
parent = getFullPathName(stdPathIn);
|
||
|
else
|
||
|
parent = getFullPathName(getCurrentDirectory(fileName_));
|
||
|
|
||
|
// remove filename from path
|
||
|
size_t endPath = parent.find_last_of(g_fileSeparator);
|
||
|
if (endPath != string::npos)
|
||
|
parent = parent.substr(0, endPath + 1);
|
||
|
|
||
|
while (!parent.empty())
|
||
|
{
|
||
|
string filepath = parent + fileName_;
|
||
|
if (fileExists(filepath.c_str()))
|
||
|
return filepath;
|
||
|
if (fileName_ == ".astylerc")
|
||
|
{
|
||
|
filepath = parent + "_astylerc";
|
||
|
if (fileExists(filepath.c_str()))
|
||
|
return filepath;
|
||
|
}
|
||
|
parent = getParentDirectory(parent);
|
||
|
}
|
||
|
return string();
|
||
|
}
|
||
|
|
||
|
// 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::getOptionFileName() const
|
||
|
{ return optionFileName; }
|
||
|
|
||
|
// 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::getProjectOptionFileName() const
|
||
|
{
|
||
|
assert(projectOptionFileName.length() > 0);
|
||
|
// remove the directory path
|
||
|
size_t start = projectOptionFileName.find_last_of(g_fileSeparator);
|
||
|
if (start == string::npos)
|
||
|
start = 0;
|
||
|
return projectOptionFileName.substr(start + 1);
|
||
|
}
|
||
|
|
||
|
// for unit testing
|
||
|
vector<string> ASConsole::getProjectOptionsVector() const
|
||
|
{ return projectOptionsVector; }
|
||
|
|
||
|
// 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;
|
||
|
}
|
||
|
|
||
|
// build a vector of argv options
|
||
|
// the program path argv[0] is excluded
|
||
|
vector<string> ASConsole::getArgvOptions(int argc, char** argv)
|
||
|
{
|
||
|
if (argc > 0)
|
||
|
astyleExePath = getFullPathName(argv[0]);
|
||
|
vector<string> argvOptions;
|
||
|
for (int i = 1; i < argc; i++)
|
||
|
{
|
||
|
argvOptions.emplace_back(string(argv[i]));
|
||
|
}
|
||
|
return argvOptions;
|
||
|
}
|
||
|
|
||
|
string ASConsole::getParam(const string& arg, const char* op)
|
||
|
{
|
||
|
return arg.substr(strlen(op));
|
||
|
}
|
||
|
|
||
|
void ASConsole::getTargetFilenames(string& targetFilename_,
|
||
|
vector<string>& targetFilenameVector) const
|
||
|
{
|
||
|
size_t beg = 0;
|
||
|
size_t sep = 0;
|
||
|
while (beg < targetFilename_.length())
|
||
|
{
|
||
|
// find next target
|
||
|
sep = targetFilename_.find_first_of(",;", beg);
|
||
|
if (sep == string::npos)
|
||
|
sep = targetFilename_.length();
|
||
|
string fileExtension = targetFilename_.substr(beg, sep - beg);
|
||
|
beg = sep + 1;
|
||
|
// remove whitespace
|
||
|
while (fileExtension.length() > 0
|
||
|
&& (fileExtension[0] == ' ' || fileExtension[0] == '\t'))
|
||
|
fileExtension = fileExtension.erase(0, 1);
|
||
|
while (fileExtension.length() > 0
|
||
|
&& (fileExtension[fileExtension.length() - 1] == ' '
|
||
|
|| fileExtension[fileExtension.length() - 1] == '\t'))
|
||
|
fileExtension = fileExtension.erase(fileExtension.length() - 1, 1);
|
||
|
if (fileExtension.length() > 0)
|
||
|
targetFilenameVector.emplace_back(fileExtension);
|
||
|
}
|
||
|
if (targetFilenameVector.empty())
|
||
|
{
|
||
|
fprintf(stderr, _("Missing filename in %s\n"), targetFilename_.c_str());
|
||
|
error();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 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();
|
||
|
}
|
||
|
|
||
|
// read a file into the stringstream 'in'
|
||
|
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 file", fileName_.c_str());
|
||
|
char* data = new (nothrow) char[blockSize];
|
||
|
if (data == nullptr)
|
||
|
error("Cannot allocate memory to open file", fileName_.c_str());
|
||
|
fin.read(data, blockSize);
|
||
|
if (fin.bad())
|
||
|
error("Cannot read 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 = encode.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 = encode.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 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::setOptionFileName(const string& name)
|
||
|
{ optionFileName = name; }
|
||
|
|
||
|
void ASConsole::setOrigSuffix(const string& suffix)
|
||
|
{ origSuffix = suffix; }
|
||
|
|
||
|
void ASConsole::setPreserveDate(bool state)
|
||
|
{ preserveDate = state; }
|
||
|
|
||
|
void ASConsole::setProjectOptionFileName(const string& optfilepath)
|
||
|
{ projectOptionFileName = optfilepath; }
|
||
|
|
||
|
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 wildcards A vector of wildcards to be processed (e.g. *.cpp).
|
||
|
*/
|
||
|
void ASConsole::getFileNames(const string& directory, const vector<string>& wildcards)
|
||
|
{
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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
|
||
|
for (const string& wildcard : wildcards)
|
||
|
{
|
||
|
if (wildcmp(wildcard.c_str(), findFileData.cFileName))
|
||
|
{
|
||
|
if (isExcluded)
|
||
|
printMsg(_("Exclude %s\n"), filePathName.substr(mainDirectoryLength));
|
||
|
else
|
||
|
fileName.emplace_back(filePathName);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
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 (const string& subDirectoryName : subDirectory)
|
||
|
getFileNames(subDirectoryName, wildcards);
|
||
|
}
|
||
|
|
||
|
// WINDOWS function to get the full path name from the relative path name
|
||
|
// Return the full path name or an empty string if failed.
|
||
|
string ASConsole::getFullPathName(const string& relativePath) const
|
||
|
{
|
||
|
char fullPath[MAX_PATH];
|
||
|
GetFullPathName(relativePath.c_str(), MAX_PATH, fullPath, nullptr);
|
||
|
return fullPath;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 check for a HOME directory
|
||
|
*
|
||
|
* @param absPath The path to be evaluated.
|
||
|
* @returns true if absPath is HOME or is an invalid absolute
|
||
|
* path, false otherwise.
|
||
|
*/
|
||
|
bool ASConsole::isHomeOrInvalidAbsPath(const string& absPath) const
|
||
|
{
|
||
|
const char* const env = getenv("USERPROFILE");
|
||
|
if (env == nullptr)
|
||
|
return true;
|
||
|
|
||
|
if (absPath.c_str() == env)
|
||
|
return true;
|
||
|
|
||
|
if (absPath.compare(0, strlen(env), env) != 0)
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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* const 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), {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} };
|
||
|
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
|
||
|
{
|
||
|
const char* const 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 wildcards A vector of wildcards to be processed (e.g. *.cpp).
|
||
|
*/
|
||
|
void ASConsole::getFileNames(const string& directory, const vector<string>& wildcards)
|
||
|
{
|
||
|
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
|
||
|
for (const string& wildcard : wildcards)
|
||
|
{
|
||
|
if (wildcmp(wildcard.c_str(), entry->d_name) != 0)
|
||
|
{
|
||
|
if (isExcluded)
|
||
|
printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
|
||
|
else
|
||
|
fileName.emplace_back(entryFilepath);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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.begin() + firstEntry, fileName.end());
|
||
|
|
||
|
// 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], wildcards);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// LINUX function to get the full path name from the relative path name
|
||
|
// Return the full path name or an empty string if failed.
|
||
|
string ASConsole::getFullPathName(const string& relativePath) const
|
||
|
{
|
||
|
// ignore realPath attribute warning, only with cmake
|
||
|
#pragma GCC diagnostic push
|
||
|
#pragma GCC diagnostic ignored "-Wunused-result"
|
||
|
char fullPath[PATH_MAX];
|
||
|
fullPath[0] = '\0';
|
||
|
realpath(relativePath.c_str(), fullPath);
|
||
|
return fullPath;
|
||
|
#pragma GCC diagnostic pop
|
||
|
}
|
||
|
|
||
|
// LINUX function to get the documentation file path prefix
|
||
|
// from the executable file path.
|
||
|
// Return the documentation path prefix or an empty string if failed.
|
||
|
string ASConsole::getHtmlInstallPrefix() const
|
||
|
{
|
||
|
string astyleHtmlPrefix = astyleExePath;
|
||
|
size_t end = astyleHtmlPrefix.find("/bin/");
|
||
|
if (end == string::npos)
|
||
|
return "";
|
||
|
astyleHtmlPrefix = astyleHtmlPrefix.substr(0, end);
|
||
|
return astyleHtmlPrefix;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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 check for a HOME directory
|
||
|
*
|
||
|
* @param absPath The path to be evaluated.
|
||
|
* @returns true if absPath is HOME or is an invalid absolute
|
||
|
* path, false otherwise.
|
||
|
*/
|
||
|
bool ASConsole::isHomeOrInvalidAbsPath(const string& absPath) const
|
||
|
{
|
||
|
const char* const env = getenv("HOME");
|
||
|
if (env == nullptr)
|
||
|
return true;
|
||
|
|
||
|
if (absPath.c_str() == env)
|
||
|
return true;
|
||
|
|
||
|
if (absPath.compare(0, strlen(env), env) != 0)
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 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
|
||
|
{
|
||
|
#ifdef __APPLE__
|
||
|
string htmlDefaultPrefix = "/usr/local";
|
||
|
#else
|
||
|
string htmlDefaultPrefix = "/usr";
|
||
|
#endif
|
||
|
string htmlDefaultPath = htmlDefaultPrefix + "/share/doc/astyle/html/";
|
||
|
string htmlDefaultFile = "astyle.html";
|
||
|
string htmlFilePath;
|
||
|
struct stat statbuf;
|
||
|
|
||
|
// build html path
|
||
|
if (filePathIn == nullptr)
|
||
|
{
|
||
|
string htmlPrefix = getHtmlInstallPrefix();
|
||
|
if (htmlPrefix.empty())
|
||
|
htmlFilePath = htmlDefaultPrefix + htmlDefaultPath + htmlDefaultFile;
|
||
|
else
|
||
|
htmlFilePath = htmlPrefix + 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* const envPaths = getenv("PATH");
|
||
|
if (envPaths == nullptr)
|
||
|
error("Cannot read PATH environment variable", "");
|
||
|
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
|
||
|
|
||
|
/**
|
||
|
* Returns the parent directory of absPath. If absPath is not a valid absolute
|
||
|
* path or if it does not have a parent, an empty string is returned.
|
||
|
*
|
||
|
* @param absPath The initial directory.
|
||
|
* @return The parent directory of absPath, or an empty string if
|
||
|
* one cannot be found.
|
||
|
*/
|
||
|
string ASConsole::getParentDirectory(const string& absPath) const
|
||
|
{
|
||
|
if (isHomeOrInvalidAbsPath(absPath))
|
||
|
{
|
||
|
return string();
|
||
|
}
|
||
|
size_t offset = absPath.size() - 1;
|
||
|
if (absPath[absPath.size() - 1] == g_fileSeparator)
|
||
|
{
|
||
|
offset -= 1;
|
||
|
}
|
||
|
size_t idx = absPath.rfind(g_fileSeparator, offset);
|
||
|
if (idx == string::npos)
|
||
|
{
|
||
|
return string();
|
||
|
}
|
||
|
string str = absPath.substr(0, idx + 1);
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
// get individual file names from the command-line file path
|
||
|
void ASConsole::getFilePaths(const string& filePath)
|
||
|
{
|
||
|
fileName.clear();
|
||
|
targetDirectory = string();
|
||
|
targetFilename = string();
|
||
|
vector<string> targetFilenameVector;
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
// 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();
|
||
|
}
|
||
|
|
||
|
bool hasMultipleTargets = false;
|
||
|
if (targetFilename.find_first_of(",;") != string::npos)
|
||
|
hasMultipleTargets = true;
|
||
|
|
||
|
// display directory name for wildcard processing
|
||
|
if (hasWildcard)
|
||
|
{
|
||
|
printSeparatingLine();
|
||
|
printMsg(_("Directory %s\n"), targetDirectory + g_fileSeparator + targetFilename);
|
||
|
}
|
||
|
|
||
|
// clear exclude hits vector
|
||
|
size_t excludeHitsVectorSize = excludeHitsVector.size();
|
||
|
for (size_t ix = 0; ix < excludeHitsVectorSize; ix++)
|
||
|
excludeHitsVector[ix] = false;
|
||
|
|
||
|
// create a vector of paths and file names to process
|
||
|
if (hasWildcard || isRecursive || hasMultipleTargets)
|
||
|
{
|
||
|
getTargetFilenames(targetFilename, targetFilenameVector);
|
||
|
getFileNames(targetDirectory, targetFilenameVector);
|
||
|
}
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
// Check if a file exists
|
||
|
bool ASConsole::fileExists(const char* file) const
|
||
|
{
|
||
|
struct stat buf;
|
||
|
return (stat(file, &buf) == 0);
|
||
|
}
|
||
|
|
||
|
bool ASConsole::fileNameVectorIsEmpty() const
|
||
|
{
|
||
|
return fileNameVector.empty();
|
||
|
}
|
||
|
|
||
|
bool ASConsole::isOption(const string& arg, const char* op)
|
||
|
{
|
||
|
return arg == op;
|
||
|
}
|
||
|
|
||
|
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 << " Multiple file extensions may be separated by a comma.\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 << "Option Files:\n";
|
||
|
cout << "-------------\n";
|
||
|
cout << " Artistic Style looks for a default option file and/or a project\n";
|
||
|
cout << " option file in the following order:\n";
|
||
|
cout << " 1. The command line options have precedence.\n";
|
||
|
cout << " 2. The project option file has precedence over the default file\n";
|
||
|
cout << " o the file name indicated by the --project= command line option.\n";
|
||
|
cout << " o the file named .astylerc or _ astylerc.\n";
|
||
|
cout << " o the file name identified by ARTISTIC_STYLE_PROJECT_OPTIONS.\n";
|
||
|
cout << " o the file is disabled by --project=none on the command line.\n";
|
||
|
cout << " 3. The default option file that can be used for all projects.\n";
|
||
|
cout << " o the file path indicated by the --options= command line option.\n";
|
||
|
cout << " o the file path indicated by ARTISTIC_STYLE_OPTIONS.\n";
|
||
|
cout << " o the file named .astylerc in the HOME directory (for Linux).\n";
|
||
|
cout << " o the file name astylerc in the APPDATA directory (for Windows).\n";
|
||
|
cout << " o the file is disabled by --project=none on the command line.\n";
|
||
|
cout << " Long options within the option files may be written without '--'.\n";
|
||
|
cout << " Line-end comments begin with a '#'.\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, with broken closing headers.\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=ratliff OR --style=banner OR -A6\n";
|
||
|
cout << " Ratliff 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=webkit OR -A17\n";
|
||
|
cout << " WebKit style formatting/indenting.\n";
|
||
|
cout << " Linux braces, with attached closing headers.\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 -xe\n";
|
||
|
cout << " Delete empty lines.\n";
|
||
|
cout << " It will NOT delete lines added by the break-blocks options.\n";
|
||
|
cout << endl;
|
||
|
cout << " --delete-multiple-empty-lines OR -xm\n";
|
||
|
cout << " Delete consecutive empty lines.\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 << " --break-return-type OR -xB\n";
|
||
|
cout << " --break-return-type-decl OR -xD\n";
|
||
|
cout << " Break the return type from the function name. Options are\n";
|
||
|
cout << " for the function definitions and the function declarations.\n";
|
||
|
cout << endl;
|
||
|
cout << " --attach-return-type OR -xf\n";
|
||
|
cout << " --attach-return-type-decl OR -xh\n";
|
||
|
cout << " Attach the return type to the function name. Options are\n";
|
||
|
cout << " for the function definitions and the function declarations.\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 << " --options=none\n";
|
||
|
cout << " Specify a default option file #### to read and use.\n";
|
||
|
cout << " It must contain a file path and a file name.\n";
|
||
|
cout << " 'none' disables the default option file.\n";
|
||
|
cout << endl;
|
||
|
cout << " --project\n";
|
||
|
cout << " --project=####\n";
|
||
|
cout << " --project=none\n";
|
||
|
cout << " Specify a project option file #### to read and use.\n";
|
||
|
cout << " It must contain a file name only, without a directory path.\n";
|
||
|
cout << " The file should be included in the project top-level directory.\n";
|
||
|
cout << " The default file name is .astylerc or _astylerc.\n";
|
||
|
cout << " 'none' disables the project or environment variable file.\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 << " --stdin=####\n";
|
||
|
cout << " Use the file path #### as input to single file formatting.\n";
|
||
|
cout << " This is a replacement for redirection.\n";
|
||
|
cout << endl;
|
||
|
cout << " --stdout=####\n";
|
||
|
cout << " Use the file path #### as output from single file formatting.\n";
|
||
|
cout << " This is a replacement for redirection.\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 (const string& fileNameVectorName : fileNameVector)
|
||
|
{
|
||
|
getFilePaths(fileNameVectorName);
|
||
|
|
||
|
// loop thru fileName vector formatting the files
|
||
|
for (const string& file : fileName)
|
||
|
formatFile(file);
|
||
|
}
|
||
|
|
||
|
// files are processed, display stats
|
||
|
if (isVerbose)
|
||
|
printVerboseStats(startTime);
|
||
|
}
|
||
|
|
||
|
// process options from the command line and option files
|
||
|
// build the vectors fileNameVector, excludeVector, optionsVector,
|
||
|
// projectOptionsVector and fileOptionsVector
|
||
|
void ASConsole::processOptions(const vector<string>& argvOptions)
|
||
|
{
|
||
|
bool ok = true;
|
||
|
bool optionFileRequired = false;
|
||
|
bool shouldParseOptionFile = true;
|
||
|
bool projectOptionFileRequired = false;
|
||
|
bool shouldParseProjectOptionFile = true;
|
||
|
string projectOptionArg; // save for display
|
||
|
|
||
|
// get command line options
|
||
|
for (string arg : argvOptions)
|
||
|
{
|
||
|
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"))
|
||
|
{
|
||
|
optionFileRequired = false;
|
||
|
shouldParseOptionFile = false;
|
||
|
optionFileName = "";
|
||
|
}
|
||
|
else if (isParamOption(arg, "--options="))
|
||
|
{
|
||
|
optionFileName = getParam(arg, "--options=");
|
||
|
standardizePath(optionFileName);
|
||
|
optionFileName = getFullPathName(optionFileName);
|
||
|
optionFileRequired = true;
|
||
|
}
|
||
|
else if (isOption(arg, "--project=none"))
|
||
|
{
|
||
|
projectOptionFileRequired = false;
|
||
|
shouldParseProjectOptionFile = false;
|
||
|
setProjectOptionFileName("");
|
||
|
}
|
||
|
else if (isParamOption(arg, "--project="))
|
||
|
{
|
||
|
projectOptionFileName = getParam(arg, "--project=");
|
||
|
standardizePath(projectOptionFileName);
|
||
|
projectOptionFileRequired = true;
|
||
|
shouldParseProjectOptionFile = false;
|
||
|
projectOptionArg = projectOptionFileName;
|
||
|
}
|
||
|
else if (isOption(arg, "--project"))
|
||
|
{
|
||
|
projectOptionFileName = ".astylerc";
|
||
|
projectOptionFileRequired = true;
|
||
|
shouldParseProjectOptionFile = false;
|
||
|
projectOptionArg = projectOptionFileName;
|
||
|
}
|
||
|
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 (isParamOption(arg, "--stdin="))
|
||
|
{
|
||
|
string path = getParam(arg, "--stdin=");
|
||
|
standardizePath(path);
|
||
|
setStdPathIn(path);
|
||
|
}
|
||
|
else if (isParamOption(arg, "--stdout="))
|
||
|
{
|
||
|
string path = getParam(arg, "--stdout=");
|
||
|
standardizePath(path);
|
||
|
setStdPathOut(path);
|
||
|
}
|
||
|
else if (arg[0] == '-')
|
||
|
{
|
||
|
optionsVector.emplace_back(arg);
|
||
|
}
|
||
|
else // file-name
|
||
|
{
|
||
|
standardizePath(arg);
|
||
|
fileNameVector.emplace_back(arg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get option file path and name
|
||
|
if (shouldParseOptionFile)
|
||
|
{
|
||
|
if (optionFileName.empty())
|
||
|
{
|
||
|
const char* const env = getenv("ARTISTIC_STYLE_OPTIONS");
|
||
|
if (env != nullptr)
|
||
|
{
|
||
|
setOptionFileName(env);
|
||
|
standardizePath(optionFileName);
|
||
|
optionFileName = getFullPathName(optionFileName);
|
||
|
}
|
||
|
}
|
||
|
// for Linux
|
||
|
if (optionFileName.empty())
|
||
|
{
|
||
|
const char* const env = getenv("HOME");
|
||
|
if (env != nullptr)
|
||
|
{
|
||
|
string name = string(env) + "/.astylerc";
|
||
|
if (fileExists(name.c_str()))
|
||
|
setOptionFileName(name);
|
||
|
}
|
||
|
}
|
||
|
// for Windows
|
||
|
if (optionFileName.empty())
|
||
|
{
|
||
|
const char* const env = getenv("APPDATA");
|
||
|
if (env != nullptr)
|
||
|
{
|
||
|
string name = string(env) + "\\astylerc";
|
||
|
if (fileExists(name.c_str()))
|
||
|
setOptionFileName(name);
|
||
|
}
|
||
|
}
|
||
|
// for Windows
|
||
|
// NOTE: depreciated with release 3.1, remove when appropriate
|
||
|
// there is NO test data for this option
|
||
|
if (optionFileName.empty())
|
||
|
{
|
||
|
const char* const env = getenv("USERPROFILE");
|
||
|
if (env != nullptr)
|
||
|
{
|
||
|
string name = string(env) + "\\astylerc";
|
||
|
if (fileExists(name.c_str()))
|
||
|
setOptionFileName(name);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// find project option file
|
||
|
if (projectOptionFileRequired)
|
||
|
{
|
||
|
string optfilepath = findProjectOptionFilePath(projectOptionFileName);
|
||
|
if (optfilepath.empty() || projectOptionArg.empty())
|
||
|
error(_("Cannot open project option file"), projectOptionArg.c_str());
|
||
|
standardizePath(optfilepath);
|
||
|
setProjectOptionFileName(optfilepath);
|
||
|
}
|
||
|
if (shouldParseProjectOptionFile)
|
||
|
{
|
||
|
const char* const env = getenv("ARTISTIC_STYLE_PROJECT_OPTIONS");
|
||
|
if (env != nullptr)
|
||
|
{
|
||
|
string optfilepath = findProjectOptionFilePath(env);
|
||
|
standardizePath(optfilepath);
|
||
|
setProjectOptionFileName(optfilepath);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASOptions options(formatter, *this);
|
||
|
if (!optionFileName.empty())
|
||
|
{
|
||
|
stringstream optionsIn;
|
||
|
if (!fileExists(optionFileName.c_str()))
|
||
|
error(_("Cannot open default option file"), optionFileName.c_str());
|
||
|
FileEncoding encoding = readFile(optionFileName, optionsIn);
|
||
|
// bypass a BOM, all BOMs have been converted to utf-8
|
||
|
if (encoding == UTF_8BOM || encoding == UTF_16LE || encoding == UTF_16BE)
|
||
|
{
|
||
|
char buf[4];
|
||
|
optionsIn.get(buf, 4);
|
||
|
assert(strcmp(buf, "\xEF\xBB\xBF") == 0);
|
||
|
}
|
||
|
options.importOptions(optionsIn, fileOptionsVector);
|
||
|
ok = options.parseOptions(fileOptionsVector,
|
||
|
string(_("Invalid default options:")));
|
||
|
}
|
||
|
else if (optionFileRequired)
|
||
|
error(_("Cannot open default option file"), optionFileName.c_str());
|
||
|
|
||
|
if (!ok)
|
||
|
{
|
||
|
(*errorStream) << options.getOptionErrors();
|
||
|
(*errorStream) << _("For help on options type 'astyle -h'") << endl;
|
||
|
error();
|
||
|
}
|
||
|
|
||
|
if (!projectOptionFileName.empty())
|
||
|
{
|
||
|
stringstream projectOptionsIn;
|
||
|
if (!fileExists(projectOptionFileName.c_str()))
|
||
|
error(_("Cannot open project option file"), projectOptionFileName.c_str());
|
||
|
FileEncoding encoding = readFile(projectOptionFileName, projectOptionsIn);
|
||
|
// bypass a BOM, all BOMs have been converted to utf-8
|
||
|
if (encoding == UTF_8BOM || encoding == UTF_16LE || encoding == UTF_16BE)
|
||
|
{
|
||
|
char buf[4];
|
||
|
projectOptionsIn.get(buf, 4);
|
||
|
assert(strcmp(buf, "\xEF\xBB\xBF") == 0);
|
||
|
}
|
||
|
options.importOptions(projectOptionsIn, projectOptionsVector);
|
||
|
ok = options.parseOptions(projectOptionsVector,
|
||
|
string(_("Invalid project options:")));
|
||
|
}
|
||
|
|
||
|
if (!ok)
|
||
|
{
|
||
|
(*errorStream) << options.getOptionErrors();
|
||
|
(*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();
|
||
|
(*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;
|
||
|
fab.fab$b_fns = 0;
|
||
|
fab.fab$l_naml = &naml;
|
||
|
naml = cc$rms_naml;
|
||
|
strcpy(sess, path.c_str());
|
||
|
naml.naml$l_long_filename = (char*) sess;
|
||
|
naml.naml$l_long_filename_size = path.length();
|
||
|
naml.naml$l_long_expand = less;
|
||
|
naml.naml$l_long_expand_alloc = sizeof(less);
|
||
|
naml.naml$l_esa = sess;
|
||
|
naml.naml$b_ess = sizeof(sess);
|
||
|
naml.naml$v_no_short_upcase = 1;
|
||
|
r0_status = sys$parse(&fab);
|
||
|
if (r0_status == RMS$_SYN)
|
||
|
{
|
||
|
error("File syntax error", path.c_str());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!$VMS_STATUS_SUCCESS(r0_status))
|
||
|
{
|
||
|
(void) lib$signal(r0_status);
|
||
|
}
|
||
|
}
|
||
|
less[naml.naml$l_long_expand_size - naml.naml$b_ver] = '\0';
|
||
|
sess[naml.naml$b_esl - naml.naml$b_ver] = '\0';
|
||
|
if (naml.naml$l_long_expand_size > naml.naml$b_esl)
|
||
|
{
|
||
|
path = decc$translate_vms(less);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
path = decc$translate_vms(sess);
|
||
|
}
|
||
|
#endif /* __VMS */
|
||
|
|
||
|
// make sure separators are correct type (Windows or Linux)
|
||
|
for (size_t i = 0; i < path.length(); i++)
|
||
|
{
|
||
|
i = path.find_first_of("/\\", i);
|
||
|
if (i == string::npos)
|
||
|
break;
|
||
|
path[i] = g_fileSeparator;
|
||
|
}
|
||
|
// remove beginning separator if requested
|
||
|
if (removeBeginningSeparator && (path[0] == g_fileSeparator))
|
||
|
path.erase(0, 1);
|
||
|
}
|
||
|
|
||
|
void ASConsole::printMsg(const char* msg, const string& data) const
|
||
|
{
|
||
|
if (isQuiet)
|
||
|
return;
|
||
|
printf(msg, data.c_str());
|
||
|
}
|
||
|
|
||
|
void ASConsole::printSeparatingLine() const
|
||
|
{
|
||
|
string line;
|
||
|
for (size_t i = 0; i < 60; i++)
|
||
|
line.append("-");
|
||
|
printMsg("%s\n", line);
|
||
|
}
|
||
|
|
||
|
void ASConsole::printVerboseHeader() const
|
||
|
{
|
||
|
assert(isVerbose);
|
||
|
if (isQuiet)
|
||
|
return;
|
||
|
// get the date
|
||
|
time_t lt;
|
||
|
char str[20];
|
||
|
lt = time(nullptr);
|
||
|
struct tm* ptr = localtime(<);
|
||
|
strftime(str, 20, "%x", ptr);
|
||
|
// print the header
|
||
|
// 60 is the length of the separator in printSeparatingLine()
|
||
|
string header = "Artistic Style " + string(g_version);
|
||
|
size_t numSpaces = 60 - header.length() - strlen(str);
|
||
|
header.append(numSpaces, ' ');
|
||
|
header.append(str);
|
||
|
header.append("\n");
|
||
|
printf("%s", header.c_str());
|
||
|
// print option files
|
||
|
if (!optionFileName.empty())
|
||
|
printf(_("Default option file %s\n"), optionFileName.c_str());
|
||
|
// NOTE: depreciated with release 3.1, remove when appropriate
|
||
|
if (!optionFileName.empty())
|
||
|
{
|
||
|
const char* const env = getenv("USERPROFILE");
|
||
|
if (env != nullptr && optionFileName == string(env) + "\\astylerc")
|
||
|
printf("The above option file has been DEPRECIATED\n");
|
||
|
}
|
||
|
// end depreciated
|
||
|
if (!projectOptionFileName.empty())
|
||
|
printf(_("Project option file %s\n"), projectOptionFileName.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;
|
||
|
// NOTE: lround is not supported by MinGW and Embarcadero
|
||
|
int minsec = int(secs + .5);
|
||
|
printf(_("%d min %d sec "), min, minsec);
|
||
|
}
|
||
|
|
||
|
string lines = getNumberFormat(linesOut);
|
||
|
printf(_("%s lines\n"), lines.c_str());
|
||
|
printf("\n");
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
// do not use emplace_back on vector<bool> until supported by macOS
|
||
|
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;
|
||
|
const char* 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 = encode.utf16LengthFromUtf8(out.str().c_str(), out.str().length());
|
||
|
char* utf16Out = new char[utf16Size];
|
||
|
size_t utf16Len = encode.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
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
char16_t* ASLibrary::formatUtf16(const char16_t* pSourceIn, // the source to be formatted
|
||
|
const char16_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
|
||
|
char16_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.
|
||
|
*/
|
||
|
char16_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 = encode.getBigEndian();
|
||
|
// return size is in number of CHARs, not char16_t
|
||
|
size_t utf16Size = (encode.utf16LengthFromUtf8(data, dataSize) + sizeof(char16_t));
|
||
|
char* utf16Out = fpMemoryAlloc((long) utf16Size);
|
||
|
if (utf16Out == nullptr)
|
||
|
return nullptr;
|
||
|
#ifdef NDEBUG
|
||
|
encode.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
|
||
|
#else
|
||
|
size_t utf16Len = encode.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
|
||
|
assert(utf16Len == utf16Size);
|
||
|
#endif
|
||
|
assert(utf16Size == (encode.utf16len(reinterpret_cast<char16_t*>(utf16Out)) + 1) * sizeof(char16_t));
|
||
|
return reinterpret_cast<char16_t*>(utf16Out);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Convert utf16 strings to utf-8.
|
||
|
* The calling function must check for errors and delete the
|
||
|
* allocated memory.
|
||
|
*/
|
||
|
char* ASLibrary::convertUtf16ToUtf8(const char16_t* utf16In) const
|
||
|
{
|
||
|
if (utf16In == nullptr)
|
||
|
return nullptr;
|
||
|
char* data = reinterpret_cast<char*>(const_cast<char16_t*>(utf16In));
|
||
|
// size must be in chars
|
||
|
size_t dataSize = encode.utf16len(utf16In) * sizeof(char16_t);
|
||
|
bool isBigEndian = encode.getBigEndian();
|
||
|
size_t utf8Size = encode.utf8LengthFromUtf16(data, dataSize, isBigEndian) + 1;
|
||
|
char* utf8Out = new (nothrow) char[utf8Size];
|
||
|
if (utf8Out == nullptr)
|
||
|
return nullptr;
|
||
|
#ifdef NDEBUG
|
||
|
encode.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
|
||
|
#else
|
||
|
size_t utf8Len = encode.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 (option file),
|
||
|
* a projectOptionsVector (project option 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;
|
||
|
string 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, "A1", "style=allman") || isOption(arg, "style=bsd") || isOption(arg, "style=break"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_ALLMAN);
|
||
|
}
|
||
|
else if (isOption(arg, "A2", "style=java") || isOption(arg, "style=attach"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_JAVA);
|
||
|
}
|
||
|
else if (isOption(arg, "A3", "style=k&r") || isOption(arg, "style=kr") || isOption(arg, "style=k/r"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_KR);
|
||
|
}
|
||
|
else if (isOption(arg, "A4", "style=stroustrup"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_STROUSTRUP);
|
||
|
}
|
||
|
else if (isOption(arg, "A5", "style=whitesmith"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_WHITESMITH);
|
||
|
}
|
||
|
else if (isOption(arg, "A15", "style=vtk"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_VTK);
|
||
|
}
|
||
|
else if (isOption(arg, "A6", "style=ratliff") || isOption(arg, "style=banner"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_RATLIFF);
|
||
|
}
|
||
|
else if (isOption(arg, "A7", "style=gnu"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_GNU);
|
||
|
}
|
||
|
else if (isOption(arg, "A8", "style=linux") || isOption(arg, "style=knf"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_LINUX);
|
||
|
}
|
||
|
else if (isOption(arg, "A9", "style=horstmann") || isOption(arg, "style=run-in"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_HORSTMANN);
|
||
|
}
|
||
|
else if (isOption(arg, "A10", "style=1tbs") || isOption(arg, "style=otbs"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_1TBS);
|
||
|
}
|
||
|
else if (isOption(arg, "A14", "style=google"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_GOOGLE);
|
||
|
}
|
||
|
else if (isOption(arg, "A16", "style=mozilla"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_MOZILLA);
|
||
|
}
|
||
|
else if (isOption(arg, "A17", "style=webkit"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_WEBKIT);
|
||
|
}
|
||
|
else if (isOption(arg, "A11", "style=pico"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_PICO);
|
||
|
}
|
||
|
else if (isOption(arg, "A12", "style=lisp") || isOption(arg, "style=python"))
|
||
|
{
|
||
|
formatter.setFormattingStyle(STYLE_LISP);
|
||
|
}
|
||
|
// 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, "xm", "delete-multiple-empty-lines"))
|
||
|
{
|
||
|
formatter.setDeleteMultipleEmptyLinesMode(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);
|
||
|
}
|
||
|
else if (isOption(arg, "xB", "break-return-type"))
|
||
|
{
|
||
|
formatter.setBreakReturnType(true);
|
||
|
}
|
||
|
else if (isOption(arg, "xD", "break-return-type-decl"))
|
||
|
{
|
||
|
formatter.setBreakReturnTypeDecl(true);
|
||
|
}
|
||
|
else if (isOption(arg, "xf", "attach-return-type"))
|
||
|
{
|
||
|
formatter.setAttachReturnType(true);
|
||
|
}
|
||
|
else if (isOption(arg, "xh", "attach-return-type-decl"))
|
||
|
{
|
||
|
formatter.setAttachReturnTypeDecl(true);
|
||
|
}
|
||
|
// To avoid compiler limit of blocks nested too deep.
|
||
|
else if (!parseOptionContinued(arg, errorInfo))
|
||
|
{
|
||
|
isOptionError(arg, errorInfo);
|
||
|
}
|
||
|
} // End of parseOption function
|
||
|
|
||
|
// Continuation of parseOption.
|
||
|
// To avoid compiler limit of blocks nested too deep.
|
||
|
// Return 'true' if the option was found and processed.
|
||
|
// Return 'false' if the option was not found.
|
||
|
bool ASOptions::parseOptionContinued(const string& arg, const string& errorInfo)
|
||
|
{
|
||
|
// Objective-C options
|
||
|
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);
|
||
|
}
|
||
|
// NOTE: depreciated options - remove when appropriate
|
||
|
// 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);
|
||
|
}
|
||
|
// end depreciated options ////////////////////////////////////////////////////////////////////
|
||
|
#ifdef ASTYLE_LIB
|
||
|
// End of options used by GUI /////////////////////////////////////////////////////////////////
|
||
|
else
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
#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
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
return true;
|
||
|
#endif
|
||
|
} // End of parseOptionContinued function
|
||
|
|
||
|
// Parse options from the option file.
|
||
|
void ASOptions::importOptions(stringstream& 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 == op;
|
||
|
}
|
||
|
|
||
|
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 << "\t" << 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
|
||
|
{
|
||
|
char16_t word = 0x0001;
|
||
|
char* byte = reinterpret_cast<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 char16_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) + (inLen % 2);
|
||
|
const char16_t* uptr = reinterpret_cast<const char16_t*>(utf16In);
|
||
|
for (size_t i = 0; i < wcharLen;)
|
||
|
{
|
||
|
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_LEAD_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 char16_t* STDCALL AStyleMainUtf16(const char16_t* pSourceIn, // the source to be formatted
|
||
|
const char16_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 char16_t on Linux
|
||
|
int sizeCheck = 2;
|
||
|
if (sizeof(char16_t) != sizeCheck)
|
||
|
{
|
||
|
fpErrorHandler(104, "char16_t is not the correct size.");
|
||
|
return nullptr;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
ASLibrary library;
|
||
|
char16_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;
|
||
|
stringstream opt(pOptions);
|
||
|
|
||
|
options.importOptions(opt, optionsVector);
|
||
|
|
||
|
bool ok = options.parseOptions(optionsVector, "Invalid Artistic Style options:");
|
||
|
if (!ok)
|
||
|
fpErrorHandler(130, options.getOptionErrors().c_str());
|
||
|
|
||
|
stringstream in(pSourceIn);
|
||
|
ASStreamIterator<stringstream> 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;
|
||
|
unique_ptr<ASConsole> console(new ASConsole(formatter));
|
||
|
|
||
|
// process command line and option files
|
||
|
// 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
|