mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
instead of adding an extra CMakeLists in .ci/travis/code_layout to build API doc, astyle and run tests (indentation, spelling, sip, doc coverage), the top CMakeLists has been adapted to allow not building core libraries and possibly just the static code layout * astyle has been moved from /src/astyle to /lib/astyle (I would propose to move all external libraries, and possibly add git submodules)
3991 lines
114 KiB
C++
Executable File
3991 lines
114 KiB
C++
Executable File
// astyle_main.cpp
|
|
// Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
|
|
// This code is licensed under the MIT License.
|
|
// License.md describes the conditions under which this software may be distributed.
|
|
|
|
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* AStyle_main source file map.
|
|
* This source file contains several classes.
|
|
* They are arranged as follows.
|
|
* ---------------------------------------
|
|
* namespace astyle {
|
|
* ASStreamIterator methods
|
|
* ASConsole methods
|
|
* // Windows specific
|
|
* // Linux specific
|
|
* ASLibrary methods
|
|
* // Windows specific
|
|
* // Linux specific
|
|
* ASOptions methods
|
|
* ASEncoding methods
|
|
* } // end of astyle namespace
|
|
* Global Area ---------------------------
|
|
* Java Native Interface functions
|
|
* AStyleMainUtf16 entry point
|
|
* AStyleMain entry point
|
|
* AStyleGetVersion entry point
|
|
* main entry point
|
|
* ---------------------------------------
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
*/
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// headers
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include "astyle_main.h"
|
|
|
|
#include <algorithm>
|
|
#include <cerrno>
|
|
#include <clocale> // needed by some compilers
|
|
#include <cstdlib>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
// includes for recursive getFileNames() function
|
|
#ifdef _WIN32
|
|
#undef UNICODE // use ASCII windows functions
|
|
#include <windows.h>
|
|
#else
|
|
#include <dirent.h>
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#ifdef __VMS
|
|
#include <unixlib.h>
|
|
#include <rms.h>
|
|
#include <ssdef.h>
|
|
#include <stsdef.h>
|
|
#include <lib$routines.h>
|
|
#include <starlet.h>
|
|
#endif /* __VMS */
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// declarations
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// turn off MinGW automatic file globbing
|
|
// this CANNOT be in the astyle namespace
|
|
#ifndef ASTYLE_LIB
|
|
int _CRT_glob = 0;
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
// astyle namespace
|
|
//----------------------------------------------------------------------------
|
|
|
|
namespace astyle {
|
|
//
|
|
// console build variables
|
|
#ifndef ASTYLE_LIB
|
|
#ifdef _WIN32
|
|
char g_fileSeparator = '\\'; // Windows file separator
|
|
bool g_isCaseSensitive = false; // Windows IS NOT case sensitive
|
|
#else
|
|
char g_fileSeparator = '/'; // Linux file separator
|
|
bool g_isCaseSensitive = true; // Linux IS case sensitive
|
|
#endif // _WIN32
|
|
#endif // ASTYLE_LIB
|
|
|
|
// java library build variables
|
|
#ifdef ASTYLE_JNI
|
|
JNIEnv* g_env;
|
|
jobject g_obj;
|
|
jmethodID g_mid;
|
|
#endif
|
|
|
|
const char* g_version = "3.0";
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ASStreamIterator class
|
|
// typename will be istringstream for GUI and istream otherwise
|
|
//-----------------------------------------------------------------------------
|
|
|
|
template<typename T>
|
|
ASStreamIterator<T>::ASStreamIterator(T* in)
|
|
{
|
|
inStream = in;
|
|
buffer.reserve(200);
|
|
eolWindows = 0;
|
|
eolLinux = 0;
|
|
eolMacOld = 0;
|
|
peekStart = 0;
|
|
prevLineDeleted = false;
|
|
checkForEmptyLine = false;
|
|
// get length of stream
|
|
inStream->seekg(0, inStream->end);
|
|
streamLength = inStream->tellg();
|
|
inStream->seekg(0, inStream->beg);
|
|
}
|
|
|
|
template<typename T>
|
|
ASStreamIterator<T>::~ASStreamIterator()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* get the length of the input stream.
|
|
* streamLength variable is set by the constructor.
|
|
*
|
|
* @return length of the input file stream, converted to an int.
|
|
*/
|
|
template<typename T>
|
|
int ASStreamIterator<T>::getStreamLength() const
|
|
{
|
|
return static_cast<int>(streamLength);
|
|
}
|
|
|
|
/**
|
|
* read the input stream, delete any end of line characters,
|
|
* and build a string that contains the input line.
|
|
*
|
|
* @return string containing the next input line minus any end of line characters
|
|
*/
|
|
template<typename T>
|
|
string ASStreamIterator<T>::nextLine(bool emptyLineWasDeleted)
|
|
{
|
|
// verify that the current position is correct
|
|
assert(peekStart == 0);
|
|
|
|
// a deleted line may be replaced if break-blocks is requested
|
|
// this sets up the compare to check for a replaced empty line
|
|
if (prevLineDeleted)
|
|
{
|
|
prevLineDeleted = false;
|
|
checkForEmptyLine = true;
|
|
}
|
|
if (!emptyLineWasDeleted)
|
|
prevBuffer = buffer;
|
|
else
|
|
prevLineDeleted = true;
|
|
|
|
// read the next record
|
|
buffer.clear();
|
|
char ch;
|
|
inStream->get(ch);
|
|
|
|
while (!inStream->eof() && ch != '\n' && ch != '\r')
|
|
{
|
|
buffer.append(1, ch);
|
|
inStream->get(ch);
|
|
}
|
|
|
|
if (inStream->eof())
|
|
{
|
|
return buffer;
|
|
}
|
|
|
|
int peekCh = inStream->peek();
|
|
|
|
// find input end-of-line characters
|
|
if (!inStream->eof())
|
|
{
|
|
if (ch == '\r') // CR+LF is windows otherwise Mac OS 9
|
|
{
|
|
if (peekCh == '\n')
|
|
{
|
|
inStream->get();
|
|
eolWindows++;
|
|
}
|
|
else
|
|
eolMacOld++;
|
|
}
|
|
else // LF is Linux, allow for improbable LF/CR
|
|
{
|
|
if (peekCh == '\r')
|
|
{
|
|
inStream->get();
|
|
eolWindows++;
|
|
}
|
|
else
|
|
eolLinux++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
inStream->clear();
|
|
}
|
|
|
|
// set output end of line characters
|
|
if (eolWindows >= eolLinux)
|
|
{
|
|
if (eolWindows >= eolMacOld)
|
|
outputEOL = "\r\n"; // Windows (CR+LF)
|
|
else
|
|
outputEOL = "\r"; // MacOld (CR)
|
|
}
|
|
else if (eolLinux >= eolMacOld)
|
|
outputEOL = "\n"; // Linux (LF)
|
|
else
|
|
outputEOL = "\r"; // MacOld (CR)
|
|
|
|
return buffer;
|
|
}
|
|
|
|
// save the current position and get the next line
|
|
// this can be called for multiple reads
|
|
// when finished peeking you MUST call peekReset()
|
|
// call this function from ASFormatter ONLY
|
|
template<typename T>
|
|
string ASStreamIterator<T>::peekNextLine()
|
|
{
|
|
assert(hasMoreLines());
|
|
string nextLine_;
|
|
char ch;
|
|
|
|
if (peekStart == 0)
|
|
peekStart = inStream->tellg();
|
|
|
|
// read the next record
|
|
inStream->get(ch);
|
|
while (!inStream->eof() && ch != '\n' && ch != '\r')
|
|
{
|
|
nextLine_.append(1, ch);
|
|
inStream->get(ch);
|
|
}
|
|
|
|
if (inStream->eof())
|
|
{
|
|
return nextLine_;
|
|
}
|
|
|
|
int peekCh = inStream->peek();
|
|
|
|
// remove end-of-line characters
|
|
if (!inStream->eof())
|
|
{
|
|
if ((peekCh == '\n' || peekCh == '\r') && peekCh != ch)
|
|
inStream->get();
|
|
}
|
|
|
|
return nextLine_;
|
|
}
|
|
|
|
// reset current position and EOF for peekNextLine()
|
|
template<typename T>
|
|
void ASStreamIterator<T>::peekReset()
|
|
{
|
|
assert(peekStart != 0);
|
|
inStream->clear();
|
|
inStream->seekg(peekStart);
|
|
peekStart = 0;
|
|
}
|
|
|
|
// save the last input line after input has reached EOF
|
|
template<typename T>
|
|
void ASStreamIterator<T>::saveLastInputLine()
|
|
{
|
|
assert(inStream->eof());
|
|
prevBuffer = buffer;
|
|
}
|
|
|
|
// return position of the get pointer
|
|
template<typename T>
|
|
streamoff ASStreamIterator<T>::tellg()
|
|
{
|
|
return inStream->tellg();
|
|
}
|
|
|
|
// check for a change in line ends
|
|
template<typename T>
|
|
bool ASStreamIterator<T>::getLineEndChange(int lineEndFormat) const
|
|
{
|
|
assert(lineEndFormat == LINEEND_DEFAULT
|
|
|| lineEndFormat == LINEEND_WINDOWS
|
|
|| lineEndFormat == LINEEND_LINUX
|
|
|| lineEndFormat == LINEEND_MACOLD);
|
|
|
|
bool lineEndChange = false;
|
|
if (lineEndFormat == LINEEND_WINDOWS)
|
|
lineEndChange = (eolLinux + eolMacOld != 0);
|
|
else if (lineEndFormat == LINEEND_LINUX)
|
|
lineEndChange = (eolWindows + eolMacOld != 0);
|
|
else if (lineEndFormat == LINEEND_MACOLD)
|
|
lineEndChange = (eolWindows + eolLinux != 0);
|
|
else
|
|
{
|
|
if (eolWindows > 0)
|
|
lineEndChange = (eolLinux + eolMacOld != 0);
|
|
else if (eolLinux > 0)
|
|
lineEndChange = (eolWindows + eolMacOld != 0);
|
|
else if (eolMacOld > 0)
|
|
lineEndChange = (eolWindows + eolLinux != 0);
|
|
}
|
|
return lineEndChange;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ASConsole class
|
|
// main function will be included only in the console build
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifndef ASTYLE_LIB
|
|
|
|
ASConsole::ASConsole(ASFormatter& formatterArg) : formatter(formatterArg)
|
|
{
|
|
errorStream = &cerr;
|
|
// command line options
|
|
isRecursive = false;
|
|
isDryRun = false;
|
|
noBackup = false;
|
|
preserveDate = false;
|
|
isVerbose = false;
|
|
isQuiet = false;
|
|
isFormattedOnly = false;
|
|
ignoreExcludeErrors = false;
|
|
ignoreExcludeErrorsDisplay = false;
|
|
optionsFileRequired = false;
|
|
useAscii = false;
|
|
// other variables
|
|
bypassBrowserOpen = false;
|
|
hasWildcard = false;
|
|
filesAreIdentical = true;
|
|
lineEndsMixed = false;
|
|
origSuffix = ".orig";
|
|
mainDirectoryLength = 0;
|
|
filesFormatted = 0;
|
|
filesUnchanged = 0;
|
|
linesOut = 0;
|
|
}
|
|
|
|
ASConsole::~ASConsole()
|
|
{}
|
|
|
|
// rewrite a stringstream converting the line ends
|
|
void ASConsole::convertLineEnds(ostringstream& out, int lineEnd)
|
|
{
|
|
assert(lineEnd == LINEEND_WINDOWS || lineEnd == LINEEND_LINUX || lineEnd == LINEEND_MACOLD);
|
|
const string& inStr = out.str(); // avoids strange looking syntax
|
|
string outStr; // the converted output
|
|
int inLength = (int)inStr.length();
|
|
for (int pos = 0; pos < inLength; pos++)
|
|
{
|
|
if (inStr[pos] == '\r')
|
|
{
|
|
if (inStr[pos + 1] == '\n')
|
|
{
|
|
// CRLF
|
|
if (lineEnd == LINEEND_CR)
|
|
{
|
|
outStr += inStr[pos]; // Delete the LF
|
|
pos++;
|
|
continue;
|
|
}
|
|
else if (lineEnd == LINEEND_LF)
|
|
{
|
|
outStr += inStr[pos + 1]; // Delete the CR
|
|
pos++;
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
outStr += inStr[pos]; // Do not change
|
|
outStr += inStr[pos + 1];
|
|
pos++;
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// CR
|
|
if (lineEnd == LINEEND_CRLF)
|
|
{
|
|
outStr += inStr[pos]; // Insert the CR
|
|
outStr += '\n'; // Insert the LF
|
|
continue;
|
|
}
|
|
else if (lineEnd == LINEEND_LF)
|
|
{
|
|
outStr += '\n'; // Insert the LF
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
outStr += inStr[pos]; // Do not change
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
else if (inStr[pos] == '\n')
|
|
{
|
|
// LF
|
|
if (lineEnd == LINEEND_CRLF)
|
|
{
|
|
outStr += '\r'; // Insert the CR
|
|
outStr += inStr[pos]; // Insert the LF
|
|
continue;
|
|
}
|
|
else if (lineEnd == LINEEND_CR)
|
|
{
|
|
outStr += '\r'; // Insert the CR
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
outStr += inStr[pos]; // Do not change
|
|
continue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
outStr += inStr[pos]; // Write the current char
|
|
}
|
|
}
|
|
// replace the stream
|
|
out.str(outStr);
|
|
}
|
|
|
|
void ASConsole::correctMixedLineEnds(ostringstream& out)
|
|
{
|
|
LineEndFormat lineEndFormat = LINEEND_DEFAULT;
|
|
if (outputEOL == "\r\n")
|
|
lineEndFormat = LINEEND_WINDOWS;
|
|
if (outputEOL == "\n")
|
|
lineEndFormat = LINEEND_LINUX;
|
|
if (outputEOL == "\r")
|
|
lineEndFormat = LINEEND_MACOLD;
|
|
convertLineEnds(out, lineEndFormat);
|
|
}
|
|
|
|
// check files for 16 or 32 bit encoding
|
|
// the file must have a Byte Order Mark (BOM)
|
|
// NOTE: some string functions don't work with NULLs (e.g. length())
|
|
FileEncoding ASConsole::detectEncoding(const char* data, size_t dataSize) const
|
|
{
|
|
FileEncoding encoding = ENCODING_8BIT;
|
|
|
|
if (dataSize >= 4 && memcmp(data, "\x00\x00\xFE\xFF", 4) == 0)
|
|
encoding = UTF_32BE;
|
|
else if (dataSize >= 4 && memcmp(data, "\xFF\xFE\x00\x00", 4) == 0)
|
|
encoding = UTF_32LE;
|
|
else if (dataSize >= 2 && memcmp(data, "\xFE\xFF", 2) == 0)
|
|
encoding = UTF_16BE;
|
|
else if (dataSize >= 2 && memcmp(data, "\xFF\xFE", 2) == 0)
|
|
encoding = UTF_16LE;
|
|
|
|
return encoding;
|
|
}
|
|
|
|
// error exit without a message
|
|
void ASConsole::error() const
|
|
{
|
|
(*errorStream) << _("\nArtistic Style has terminated") << endl;
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
// error exit with a message
|
|
void ASConsole::error(const char* why, const char* what) const
|
|
{
|
|
(*errorStream) << why << ' ' << what << endl;
|
|
error();
|
|
}
|
|
|
|
/**
|
|
* If no files have been given, use cin for input and cout for output.
|
|
*
|
|
* This is used to format text for text editors like TextWrangler (Mac).
|
|
* Do NOT display any console messages when this function is used.
|
|
*/
|
|
void ASConsole::formatCinToCout()
|
|
{
|
|
// check for files from --stdin= and --stdout=
|
|
if (!stdPathIn.empty())
|
|
{
|
|
if (!freopen(stdPathIn.c_str(), "r", stdin))
|
|
error("Cannot open input file", stdPathIn.c_str());
|
|
}
|
|
if (!stdPathOut.empty())
|
|
{
|
|
if (!freopen(stdPathOut.c_str(), "w", stdout))
|
|
error("Cannot open output file", stdPathOut.c_str());
|
|
|
|
}
|
|
// Using cin.tellg() causes problems with both Windows and Linux.
|
|
// The Windows problem occurs when the input is not Windows line-ends.
|
|
// The tellg() will be out of sequence with the get() statements.
|
|
// The Linux cin.tellg() will return -1 (invalid).
|
|
// Copying the input sequentially to a stringstream before
|
|
// formatting solves the problem for both.
|
|
istream* inStream = &cin;
|
|
stringstream outStream;
|
|
char ch;
|
|
inStream->get(ch);
|
|
while (!inStream->eof() && !inStream->fail())
|
|
{
|
|
outStream.put(ch);
|
|
inStream->get(ch);
|
|
}
|
|
ASStreamIterator<stringstream> streamIterator(&outStream);
|
|
// Windows pipe or redirection always outputs Windows line-ends.
|
|
// Linux pipe or redirection will output any line end.
|
|
#ifdef _WIN32
|
|
LineEndFormat lineEndFormat = LINEEND_DEFAULT;
|
|
#else
|
|
LineEndFormat lineEndFormat = formatter.getLineEndFormat();
|
|
#endif // _WIN32
|
|
initializeOutputEOL(lineEndFormat);
|
|
formatter.init(&streamIterator);
|
|
|
|
while (formatter.hasMoreLines())
|
|
{
|
|
cout << formatter.nextLine();
|
|
if (formatter.hasMoreLines())
|
|
{
|
|
setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
|
|
cout << outputEOL;
|
|
}
|
|
else
|
|
{
|
|
// this can happen if the file if missing a closing brace and break-blocks is requested
|
|
if (formatter.getIsLineReady())
|
|
{
|
|
setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
|
|
cout << outputEOL;
|
|
cout << formatter.nextLine();
|
|
}
|
|
}
|
|
}
|
|
cout.flush();
|
|
}
|
|
|
|
/**
|
|
* Open input file, format it, and close the output.
|
|
*
|
|
* @param fileName_ The path and name of the file to be processed.
|
|
*/
|
|
void ASConsole::formatFile(const string& fileName_)
|
|
{
|
|
stringstream in;
|
|
ostringstream out;
|
|
FileEncoding encoding = readFile(fileName_, in);
|
|
|
|
// Unless a specific language mode has been set, set the language mode
|
|
// according to the file's suffix.
|
|
if (!formatter.getModeManuallySet())
|
|
{
|
|
if (stringEndsWith(fileName_, string(".java")))
|
|
formatter.setJavaStyle();
|
|
else if (stringEndsWith(fileName_, string(".cs")))
|
|
formatter.setSharpStyle();
|
|
else
|
|
formatter.setCStyle();
|
|
}
|
|
|
|
// set line end format
|
|
string nextLine; // next output line
|
|
filesAreIdentical = true; // input and output files are identical
|
|
LineEndFormat lineEndFormat = formatter.getLineEndFormat();
|
|
initializeOutputEOL(lineEndFormat);
|
|
// do this AFTER setting the file mode
|
|
ASStreamIterator<stringstream> streamIterator(&in);
|
|
formatter.init(&streamIterator);
|
|
|
|
// format the file
|
|
while (formatter.hasMoreLines())
|
|
{
|
|
nextLine = formatter.nextLine();
|
|
out << nextLine;
|
|
linesOut++;
|
|
if (formatter.hasMoreLines())
|
|
{
|
|
setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
|
|
out << outputEOL;
|
|
}
|
|
else
|
|
{
|
|
streamIterator.saveLastInputLine(); // to compare the last input line
|
|
// this can happen if the file if missing a closing brace and break-blocks is requested
|
|
if (formatter.getIsLineReady())
|
|
{
|
|
setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
|
|
out << outputEOL;
|
|
nextLine = formatter.nextLine();
|
|
out << nextLine;
|
|
linesOut++;
|
|
streamIterator.saveLastInputLine();
|
|
}
|
|
}
|
|
|
|
if (filesAreIdentical)
|
|
{
|
|
if (streamIterator.checkForEmptyLine)
|
|
{
|
|
if (nextLine.find_first_not_of(" \t") != string::npos)
|
|
filesAreIdentical = false;
|
|
}
|
|
else if (!streamIterator.compareToInputBuffer(nextLine))
|
|
filesAreIdentical = false;
|
|
streamIterator.checkForEmptyLine = false;
|
|
}
|
|
}
|
|
// correct for mixed line ends
|
|
if (lineEndsMixed)
|
|
{
|
|
correctMixedLineEnds(out);
|
|
filesAreIdentical = false;
|
|
}
|
|
|
|
// remove targetDirectory from filename if required by print
|
|
string displayName;
|
|
if (hasWildcard)
|
|
displayName = fileName_.substr(targetDirectory.length() + 1);
|
|
else
|
|
displayName = fileName_;
|
|
|
|
// if file has changed, write the new file
|
|
if (!filesAreIdentical || streamIterator.getLineEndChange(lineEndFormat))
|
|
{
|
|
if (!isDryRun)
|
|
writeFile(fileName_, encoding, out);
|
|
printMsg(_("Formatted %s\n"), displayName);
|
|
filesFormatted++;
|
|
}
|
|
else
|
|
{
|
|
if (!isFormattedOnly)
|
|
printMsg(_("Unchanged %s\n"), displayName);
|
|
filesUnchanged++;
|
|
}
|
|
|
|
assert(formatter.getChecksumDiff() == 0);
|
|
}
|
|
|
|
// build a vector of argv options
|
|
// the program path argv[0] is excluded
|
|
vector<string> ASConsole::getArgvOptions(int argc, char** argv) const
|
|
{
|
|
vector<string> argvOptions;
|
|
for (int i = 1; i < argc; i++)
|
|
{
|
|
argvOptions.emplace_back(string(argv[i]));
|
|
}
|
|
return argvOptions;
|
|
}
|
|
|
|
// for unit testing
|
|
vector<bool> ASConsole::getExcludeHitsVector() const
|
|
{ return excludeHitsVector; }
|
|
|
|
// for unit testing
|
|
vector<string> ASConsole::getExcludeVector() const
|
|
{ return excludeVector; }
|
|
|
|
// for unit testing
|
|
vector<string> ASConsole::getFileName() const
|
|
{ return fileName; }
|
|
|
|
// for unit testing
|
|
vector<string> ASConsole::getFileNameVector() const
|
|
{ return fileNameVector; }
|
|
|
|
// for unit testing
|
|
vector<string> ASConsole::getFileOptionsVector() const
|
|
{ return fileOptionsVector; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getFilesAreIdentical() const
|
|
{ return filesAreIdentical; }
|
|
|
|
// for unit testing
|
|
int ASConsole::getFilesFormatted() const
|
|
{ return filesFormatted; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getIgnoreExcludeErrors() const
|
|
{ return ignoreExcludeErrors; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getIgnoreExcludeErrorsDisplay() const
|
|
{ return ignoreExcludeErrorsDisplay; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getIsDryRun() const
|
|
{ return isDryRun; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getIsFormattedOnly() const
|
|
{ return isFormattedOnly; }
|
|
|
|
// for unit testing
|
|
string ASConsole::getLanguageID() const
|
|
{ return localizer.getLanguageID(); }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getIsQuiet() const
|
|
{ return isQuiet; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getIsRecursive() const
|
|
{ return isRecursive; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getIsVerbose() const
|
|
{ return isVerbose; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getLineEndsMixed() const
|
|
{ return lineEndsMixed; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getNoBackup() const
|
|
{ return noBackup; }
|
|
|
|
// for unit testing
|
|
string ASConsole::getOptionsFileName() const
|
|
{ return optionsFileName; }
|
|
|
|
// for unit testing
|
|
vector<string> ASConsole::getOptionsVector() const
|
|
{ return optionsVector; }
|
|
|
|
// for unit testing
|
|
string ASConsole::getOrigSuffix() const
|
|
{ return origSuffix; }
|
|
|
|
// for unit testing
|
|
bool ASConsole::getPreserveDate() const
|
|
{ return preserveDate; }
|
|
|
|
// for unit testing
|
|
string ASConsole::getStdPathIn() const
|
|
{ return stdPathIn; }
|
|
|
|
// for unit testing
|
|
string ASConsole::getStdPathOut() const
|
|
{ return stdPathOut; }
|
|
|
|
// for unit testing
|
|
void ASConsole::setBypassBrowserOpen(bool state)
|
|
{ bypassBrowserOpen = state; }
|
|
|
|
// for unit testing
|
|
ostream* ASConsole::getErrorStream() const
|
|
{
|
|
return errorStream;
|
|
}
|
|
|
|
void ASConsole::setErrorStream(ostream* errStreamPtr)
|
|
{
|
|
errorStream = errStreamPtr;
|
|
}
|
|
|
|
string ASConsole::getParam(const string& arg, const char* op)
|
|
{
|
|
return arg.substr(strlen(op));
|
|
}
|
|
|
|
// initialize output end of line
|
|
void ASConsole::initializeOutputEOL(LineEndFormat lineEndFormat)
|
|
{
|
|
assert(lineEndFormat == LINEEND_DEFAULT
|
|
|| lineEndFormat == LINEEND_WINDOWS
|
|
|| lineEndFormat == LINEEND_LINUX
|
|
|| lineEndFormat == LINEEND_MACOLD);
|
|
|
|
outputEOL.clear(); // current line end
|
|
prevEOL.clear(); // previous line end
|
|
lineEndsMixed = false; // output has mixed line ends, LINEEND_DEFAULT only
|
|
|
|
if (lineEndFormat == LINEEND_WINDOWS)
|
|
outputEOL = "\r\n";
|
|
else if (lineEndFormat == LINEEND_LINUX)
|
|
outputEOL = "\n";
|
|
else if (lineEndFormat == LINEEND_MACOLD)
|
|
outputEOL = "\r";
|
|
else
|
|
outputEOL.clear();
|
|
}
|
|
|
|
FileEncoding ASConsole::readFile(const string& fileName_, stringstream& in) const
|
|
{
|
|
const int blockSize = 65536; // 64 KB
|
|
ifstream fin(fileName_.c_str(), ios::binary);
|
|
if (!fin)
|
|
error("Cannot open input file", fileName_.c_str());
|
|
char* data = new (nothrow) char[blockSize];
|
|
if (data == nullptr)
|
|
error("Cannot allocate memory for input file", fileName_.c_str());
|
|
fin.read(data, blockSize);
|
|
if (fin.bad())
|
|
error("Cannot read input file", fileName_.c_str());
|
|
size_t dataSize = static_cast<size_t>(fin.gcount());
|
|
FileEncoding encoding = detectEncoding(data, dataSize);
|
|
if (encoding == UTF_32BE || encoding == UTF_32LE)
|
|
error(_("Cannot process UTF-32 encoding"), fileName_.c_str());
|
|
bool firstBlock = true;
|
|
bool isBigEndian = (encoding == UTF_16BE);
|
|
while (dataSize != 0)
|
|
{
|
|
if (encoding == UTF_16LE || encoding == UTF_16BE)
|
|
{
|
|
// convert utf-16 to utf-8
|
|
size_t utf8Size = utf8_16.utf8LengthFromUtf16(data, dataSize, isBigEndian);
|
|
char* utf8Out = new (nothrow) char[utf8Size];
|
|
if (utf8Out == nullptr)
|
|
error("Cannot allocate memory for utf-8 conversion", fileName_.c_str());
|
|
size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize, isBigEndian, firstBlock, utf8Out);
|
|
assert(utf8Len == utf8Size);
|
|
in << string(utf8Out, utf8Len);
|
|
delete[] utf8Out;
|
|
}
|
|
else
|
|
in << string(data, dataSize);
|
|
fin.read(data, blockSize);
|
|
if (fin.bad())
|
|
error("Cannot read input file", fileName_.c_str());
|
|
dataSize = static_cast<size_t>(fin.gcount());
|
|
firstBlock = false;
|
|
}
|
|
fin.close();
|
|
delete[] data;
|
|
return encoding;
|
|
}
|
|
|
|
void ASConsole::setIgnoreExcludeErrors(bool state)
|
|
{ ignoreExcludeErrors = state; }
|
|
|
|
void ASConsole::setIgnoreExcludeErrorsAndDisplay(bool state)
|
|
{ ignoreExcludeErrors = state; ignoreExcludeErrorsDisplay = state; }
|
|
|
|
void ASConsole::setIsFormattedOnly(bool state)
|
|
{ isFormattedOnly = state; }
|
|
|
|
void ASConsole::setIsQuiet(bool state)
|
|
{ isQuiet = state; }
|
|
|
|
void ASConsole::setIsRecursive(bool state)
|
|
{ isRecursive = state; }
|
|
|
|
void ASConsole::setIsDryRun(bool state)
|
|
{ isDryRun = state; }
|
|
|
|
void ASConsole::setIsVerbose(bool state)
|
|
{ isVerbose = state; }
|
|
|
|
void ASConsole::setNoBackup(bool state)
|
|
{ noBackup = state; }
|
|
|
|
void ASConsole::setOptionsFileName(const string& name)
|
|
{ optionsFileName = name; }
|
|
|
|
void ASConsole::setOrigSuffix(const string& suffix)
|
|
{ origSuffix = suffix; }
|
|
|
|
void ASConsole::setPreserveDate(bool state)
|
|
{ preserveDate = state; }
|
|
|
|
void ASConsole::setStdPathIn(const string& path)
|
|
{ stdPathIn = path; }
|
|
|
|
void ASConsole::setStdPathOut(const string& path)
|
|
{ stdPathOut = path; }
|
|
|
|
// set outputEOL variable
|
|
void ASConsole::setOutputEOL(LineEndFormat lineEndFormat, const string& currentEOL)
|
|
{
|
|
if (lineEndFormat == LINEEND_DEFAULT)
|
|
{
|
|
outputEOL = currentEOL;
|
|
if (prevEOL.empty())
|
|
prevEOL = outputEOL;
|
|
if (prevEOL != outputEOL)
|
|
{
|
|
lineEndsMixed = true;
|
|
filesAreIdentical = false;
|
|
prevEOL = outputEOL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
prevEOL = currentEOL;
|
|
if (prevEOL != outputEOL)
|
|
filesAreIdentical = false;
|
|
}
|
|
}
|
|
|
|
#ifdef _WIN32 // Windows specific
|
|
|
|
/**
|
|
* WINDOWS function to display the last system error.
|
|
*/
|
|
void ASConsole::displayLastError()
|
|
{
|
|
LPSTR msgBuf;
|
|
DWORD lastError = GetLastError();
|
|
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
|
nullptr,
|
|
lastError,
|
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
|
|
(LPSTR) &msgBuf,
|
|
0,
|
|
nullptr
|
|
);
|
|
// Display the string.
|
|
(*errorStream) << "Error (" << lastError << ") " << msgBuf << endl;
|
|
// Free the buffer.
|
|
LocalFree(msgBuf);
|
|
}
|
|
|
|
/**
|
|
* WINDOWS function to get the current directory.
|
|
* NOTE: getenv("CD") does not work for Windows Vista.
|
|
* The Windows function GetCurrentDirectory is used instead.
|
|
*
|
|
* @return The path of the current directory
|
|
*/
|
|
string ASConsole::getCurrentDirectory(const string& fileName_) const
|
|
{
|
|
char currdir[MAX_PATH];
|
|
currdir[0] = '\0';
|
|
if (!GetCurrentDirectory(sizeof(currdir), currdir))
|
|
error("Cannot find file", fileName_.c_str());
|
|
return string(currdir);
|
|
}
|
|
|
|
/**
|
|
* WINDOWS function to resolve wildcards and recurse into sub directories.
|
|
* The fileName vector is filled with the path and names of files to process.
|
|
*
|
|
* @param directory The path of the directory to be processed.
|
|
* @param wildcard The wildcard to be processed (e.g. *.cpp).
|
|
*/
|
|
void ASConsole::getFileNames(const string& directory, const string& wildcard)
|
|
{
|
|
vector<string> subDirectory; // sub directories of directory
|
|
WIN32_FIND_DATA findFileData; // for FindFirstFile and FindNextFile
|
|
|
|
// Find the first file in the directory
|
|
// Find will get at least "." and "..".
|
|
string firstFile = directory + "\\*";
|
|
HANDLE hFind = FindFirstFile(firstFile.c_str(), &findFileData);
|
|
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
// Error (3) The system cannot find the path specified.
|
|
// Error (123) The filename, directory name, or volume label syntax is incorrect.
|
|
// ::FindClose(hFind); before exiting
|
|
displayLastError();
|
|
error(_("Cannot open directory"), directory.c_str());
|
|
}
|
|
|
|
// save files and sub directories
|
|
do
|
|
{
|
|
// skip hidden or read only
|
|
if (findFileData.cFileName[0] == '.'
|
|
|| (findFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
|
|
|| (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
|
|
continue;
|
|
|
|
// is this a sub directory
|
|
if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
if (!isRecursive)
|
|
continue;
|
|
// if a sub directory and recursive, save sub directory
|
|
string subDirectoryPath = directory + g_fileSeparator + findFileData.cFileName;
|
|
if (isPathExclued(subDirectoryPath))
|
|
printMsg(_("Exclude %s\n"), subDirectoryPath.substr(mainDirectoryLength));
|
|
else
|
|
subDirectory.emplace_back(subDirectoryPath);
|
|
continue;
|
|
}
|
|
|
|
// save the file name
|
|
string filePathName = directory + g_fileSeparator + findFileData.cFileName;
|
|
// check exclude before wildcmp to avoid "unmatched exclude" error
|
|
bool isExcluded = isPathExclued(filePathName);
|
|
// save file name if wildcard match
|
|
if (wildcmp(wildcard.c_str(), findFileData.cFileName))
|
|
{
|
|
if (isExcluded)
|
|
printMsg(_("Exclude %s\n"), filePathName.substr(mainDirectoryLength));
|
|
else
|
|
fileName.emplace_back(filePathName);
|
|
}
|
|
}
|
|
while (FindNextFile(hFind, &findFileData) != 0);
|
|
|
|
// check for processing error
|
|
::FindClose(hFind);
|
|
DWORD dwError = GetLastError();
|
|
if (dwError != ERROR_NO_MORE_FILES)
|
|
error("Error processing directory", directory.c_str());
|
|
|
|
// recurse into sub directories
|
|
// if not doing recursive subDirectory is empty
|
|
for (unsigned i = 0; i < subDirectory.size(); i++)
|
|
getFileNames(subDirectory[i], wildcard);
|
|
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* WINDOWS function to format a number according to the current locale.
|
|
* This formats positive integers only, no float.
|
|
*
|
|
* @param num The number to be formatted.
|
|
* @param lcid The LCID of the locale to be used for testing.
|
|
* @return The formatted number.
|
|
*/
|
|
string ASConsole::getNumberFormat(int num, size_t lcid) const
|
|
{
|
|
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
|
|
// Compilers that don't support C++ locales should still support this assert.
|
|
// The C locale should be set but not the C++.
|
|
// This function is not necessary if the C++ locale is set.
|
|
// The locale().name() return value is not portable to all compilers.
|
|
assert(locale().name() == "C");
|
|
#endif
|
|
// convert num to a string
|
|
stringstream alphaNum;
|
|
alphaNum << num;
|
|
string number = alphaNum.str();
|
|
if (useAscii)
|
|
return number;
|
|
|
|
// format the number using the Windows API
|
|
if (lcid == 0)
|
|
lcid = LOCALE_USER_DEFAULT;
|
|
int outSize = ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, nullptr, 0);
|
|
char* outBuf = new (nothrow) char[outSize];
|
|
if (outBuf == nullptr)
|
|
return number;
|
|
::GetNumberFormat(lcid, 0, number.c_str(), nullptr, outBuf, outSize);
|
|
string formattedNum(outBuf);
|
|
delete[] outBuf;
|
|
// remove the decimal
|
|
int decSize = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, nullptr, 0);
|
|
char* decBuf = new (nothrow) char[decSize];
|
|
if (decBuf == nullptr)
|
|
return number;
|
|
::GetLocaleInfo(lcid, LOCALE_SDECIMAL, decBuf, decSize);
|
|
size_t i = formattedNum.rfind(decBuf);
|
|
delete[] decBuf;
|
|
if (i != string::npos)
|
|
formattedNum.erase(i);
|
|
if (!formattedNum.length())
|
|
formattedNum = "0";
|
|
return formattedNum;
|
|
}
|
|
|
|
/**
|
|
* WINDOWS function to open a HTML file in the default browser.
|
|
*/
|
|
void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
|
|
{
|
|
struct stat statbuf;
|
|
const char* envPaths[] = { "PROGRAMFILES(X86)", "PROGRAMFILES" };
|
|
size_t pathsLen = sizeof(envPaths) / sizeof(envPaths[0]);
|
|
string htmlDefaultPath;
|
|
for (size_t i = 0; i < pathsLen; i++)
|
|
{
|
|
const char* envPath = getenv(envPaths[i]);
|
|
if (envPath == nullptr)
|
|
continue;
|
|
htmlDefaultPath = envPath;
|
|
if (htmlDefaultPath.length() > 0
|
|
&& htmlDefaultPath[htmlDefaultPath.length() - 1] == g_fileSeparator)
|
|
htmlDefaultPath.erase(htmlDefaultPath.length() - 1);
|
|
htmlDefaultPath.append("\\AStyle\\doc");
|
|
if (stat(htmlDefaultPath.c_str(), &statbuf) == 0 && statbuf.st_mode & S_IFDIR)
|
|
break;
|
|
}
|
|
htmlDefaultPath.append("\\");
|
|
|
|
// build file path
|
|
string htmlFilePath;
|
|
if (filePathIn == nullptr)
|
|
htmlFilePath = htmlDefaultPath + "astyle.html";
|
|
else
|
|
{
|
|
if (strpbrk(filePathIn, "\\/") == nullptr)
|
|
htmlFilePath = htmlDefaultPath + filePathIn;
|
|
else
|
|
htmlFilePath = filePathIn;
|
|
}
|
|
standardizePath(htmlFilePath);
|
|
if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
|
|
{
|
|
printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
|
|
return;
|
|
}
|
|
|
|
SHELLEXECUTEINFO sei = { sizeof(sei), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
sei.fMask = SEE_MASK_FLAG_NO_UI;
|
|
sei.lpVerb = "open";
|
|
sei.lpFile = htmlFilePath.c_str();
|
|
sei.nShow = SW_SHOWNORMAL;
|
|
|
|
// browser open will be bypassed in test programs
|
|
printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
|
|
if (!bypassBrowserOpen)
|
|
{
|
|
int ret = ShellExecuteEx(&sei);
|
|
if (!ret)
|
|
error(_("Command execute failure"), htmlFilePath.c_str());
|
|
}
|
|
}
|
|
|
|
#else // Linux specific
|
|
|
|
/**
|
|
* LINUX function to get the current directory.
|
|
* This is done if the fileName does not contain a path.
|
|
* It is probably from an editor sending a single file.
|
|
*
|
|
* @param fileName_ The filename is used only for the error message.
|
|
* @return The path of the current directory
|
|
*/
|
|
string ASConsole::getCurrentDirectory(const string& fileName_) const
|
|
{
|
|
char* currdir = getenv("PWD");
|
|
if (currdir == nullptr)
|
|
error("Cannot find file", fileName_.c_str());
|
|
return string(currdir);
|
|
}
|
|
|
|
/**
|
|
* LINUX function to resolve wildcards and recurse into sub directories.
|
|
* The fileName vector is filled with the path and names of files to process.
|
|
*
|
|
* @param directory The path of the directory to be processed.
|
|
* @param wildcard The wildcard to be processed (e.g. *.cpp).
|
|
*/
|
|
void ASConsole::getFileNames(const string& directory, const string& wildcard)
|
|
{
|
|
struct dirent* entry; // entry from readdir()
|
|
struct stat statbuf; // entry from stat()
|
|
vector<string> subDirectory; // sub directories of this directory
|
|
|
|
// errno is defined in <errno.h> and is set for errors in opendir, readdir, or stat
|
|
errno = 0;
|
|
|
|
DIR* dp = opendir(directory.c_str());
|
|
if (dp == nullptr)
|
|
error(_("Cannot open directory"), directory.c_str());
|
|
|
|
// save the first fileName entry for this recursion
|
|
const unsigned firstEntry = fileName.size();
|
|
|
|
// save files and sub directories
|
|
while ((entry = readdir(dp)) != nullptr)
|
|
{
|
|
// get file status
|
|
string entryFilepath = directory + g_fileSeparator + entry->d_name;
|
|
if (stat(entryFilepath.c_str(), &statbuf) != 0)
|
|
{
|
|
if (errno == EOVERFLOW) // file over 2 GB is OK
|
|
{
|
|
errno = 0;
|
|
continue;
|
|
}
|
|
perror("errno message");
|
|
error("Error getting file status in directory", directory.c_str());
|
|
}
|
|
// skip hidden or read only
|
|
if (entry->d_name[0] == '.' || !(statbuf.st_mode & S_IWUSR))
|
|
continue;
|
|
// if a sub directory and recursive, save sub directory
|
|
if (S_ISDIR(statbuf.st_mode) && isRecursive)
|
|
{
|
|
if (isPathExclued(entryFilepath))
|
|
printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
|
|
else
|
|
subDirectory.emplace_back(entryFilepath);
|
|
continue;
|
|
}
|
|
|
|
// if a file, save file name
|
|
if (S_ISREG(statbuf.st_mode))
|
|
{
|
|
// check exclude before wildcmp to avoid "unmatched exclude" error
|
|
bool isExcluded = isPathExclued(entryFilepath);
|
|
// save file name if wildcard match
|
|
if (wildcmp(wildcard.c_str(), entry->d_name) != 0)
|
|
{
|
|
if (isExcluded)
|
|
printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
|
|
else
|
|
fileName.emplace_back(entryFilepath);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (closedir(dp) != 0)
|
|
{
|
|
perror("errno message");
|
|
error("Error reading directory", directory.c_str());
|
|
}
|
|
|
|
// sort the current entries for fileName
|
|
if (firstEntry < fileName.size())
|
|
sort(&fileName[firstEntry], &fileName[fileName.size()]);
|
|
|
|
// recurse into sub directories
|
|
// if not doing recursive, subDirectory is empty
|
|
if (subDirectory.size() > 1)
|
|
sort(subDirectory.begin(), subDirectory.end());
|
|
for (unsigned i = 0; i < subDirectory.size(); i++)
|
|
{
|
|
getFileNames(subDirectory[i], wildcard);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* LINUX function to get locale information and call getNumberFormat.
|
|
* This formats positive integers only, no float.
|
|
*
|
|
* @param num The number to be formatted.
|
|
* size_t is for compatibility with the Windows function.
|
|
* @return The formatted number.
|
|
*/
|
|
string ASConsole::getNumberFormat(int num, size_t /*lcid*/) const
|
|
{
|
|
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
|
|
// Compilers that don't support C++ locales should still support this assert.
|
|
// The C locale should be set but not the C++.
|
|
// This function is not necessary if the C++ locale is set.
|
|
// The locale().name() return value is not portable to all compilers.
|
|
assert(locale().name() == "C");
|
|
#endif
|
|
|
|
// get the locale info
|
|
struct lconv* lc;
|
|
lc = localeconv();
|
|
|
|
// format the number
|
|
return getNumberFormat(num, lc->grouping, lc->thousands_sep);
|
|
}
|
|
|
|
/**
|
|
* LINUX function to format a number according to the current locale.
|
|
* This formats positive integers only, no float.
|
|
*
|
|
* @param num The number to be formatted.
|
|
* @param groupingArg The grouping string from the locale.
|
|
* @param separator The thousands group separator from the locale.
|
|
* @return The formatted number.
|
|
*/
|
|
string ASConsole::getNumberFormat(int num, const char* groupingArg, const char* separator) const
|
|
{
|
|
// convert num to a string
|
|
stringstream alphaNum;
|
|
alphaNum << num;
|
|
string number = alphaNum.str();
|
|
// format the number from right to left
|
|
string formattedNum;
|
|
size_t ig = 0; // grouping index
|
|
int grouping = groupingArg[ig];
|
|
int i = number.length();
|
|
// check for no grouping
|
|
if (grouping == 0)
|
|
grouping = number.length();
|
|
while (i > 0)
|
|
{
|
|
// extract a group of numbers
|
|
string group;
|
|
if (i < grouping)
|
|
group = number;
|
|
else
|
|
group = number.substr(i - grouping);
|
|
// update formatted number
|
|
formattedNum.insert(0, group);
|
|
i -= grouping;
|
|
if (i < 0)
|
|
i = 0;
|
|
if (i > 0)
|
|
formattedNum.insert(0, separator);
|
|
number.erase(i);
|
|
// update grouping
|
|
if (groupingArg[ig] != '\0'
|
|
&& groupingArg[ig + 1] != '\0')
|
|
grouping = groupingArg[++ig];
|
|
}
|
|
return formattedNum;
|
|
}
|
|
|
|
/**
|
|
* LINUX function to open a HTML file in the default browser.
|
|
* Use xdg-open from freedesktop.org cross-desktop compatibility suite xdg-utils.
|
|
* see http://portland.freedesktop.org/wiki/
|
|
* This is installed on most modern distributions.
|
|
*/
|
|
void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
|
|
{
|
|
struct stat statbuf;
|
|
string htmlDefaultPath = "/usr/share/doc/astyle/html/";
|
|
string htmlDefaultFile = "astyle.html";
|
|
|
|
// build file path
|
|
string htmlFilePath;
|
|
if (filePathIn == nullptr)
|
|
htmlFilePath = htmlDefaultPath + htmlDefaultFile;
|
|
else
|
|
{
|
|
if (strpbrk(filePathIn, "\\/") == nullptr)
|
|
htmlFilePath = htmlDefaultPath + filePathIn;
|
|
else
|
|
htmlFilePath = filePathIn;
|
|
}
|
|
standardizePath(htmlFilePath);
|
|
if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
|
|
{
|
|
printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
|
|
return;
|
|
}
|
|
|
|
// get search paths
|
|
const char* envPaths = getenv("PATH");
|
|
if (envPaths == nullptr)
|
|
envPaths = "?";
|
|
size_t envlen = strlen(envPaths);
|
|
char* paths = new char[envlen + 1];
|
|
strcpy(paths, envPaths);
|
|
// find xdg-open (usually in /usr/bin)
|
|
// Mac uses open instead
|
|
#ifdef __APPLE__
|
|
const char* fileOpen = "open";
|
|
#else
|
|
const char* fileOpen = "xdg-open";
|
|
#endif
|
|
string searchPath;
|
|
char* searchDir = strtok(paths, ":");
|
|
while (searchDir != nullptr)
|
|
{
|
|
searchPath = searchDir;
|
|
if (searchPath.length() > 0
|
|
&& searchPath[searchPath.length() - 1] != g_fileSeparator)
|
|
searchPath.append(string(1, g_fileSeparator));
|
|
searchPath.append(fileOpen);
|
|
if (stat(searchPath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
|
|
break;
|
|
searchDir = strtok(nullptr, ":");
|
|
}
|
|
delete[] paths;
|
|
if (searchDir == nullptr)
|
|
error(_("Command is not installed"), fileOpen);
|
|
|
|
// browser open will be bypassed in test programs
|
|
printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
|
|
if (!bypassBrowserOpen)
|
|
{
|
|
execlp(fileOpen, fileOpen, htmlFilePath.c_str(), nullptr);
|
|
// execlp will NOT return if successful
|
|
error(_("Command execute failure"), fileOpen);
|
|
}
|
|
}
|
|
|
|
#endif // _WIN32
|
|
|
|
// get individual file names from the command-line file path
|
|
void ASConsole::getFilePaths(const string& filePath)
|
|
{
|
|
fileName.clear();
|
|
targetDirectory = string();
|
|
targetFilename = string();
|
|
|
|
// separate directory and file name
|
|
size_t separator = filePath.find_last_of(g_fileSeparator);
|
|
if (separator == string::npos)
|
|
{
|
|
// if no directory is present, use the currently active directory
|
|
targetDirectory = getCurrentDirectory(filePath);
|
|
targetFilename = filePath;
|
|
mainDirectoryLength = targetDirectory.length() + 1; // +1 includes trailing separator
|
|
}
|
|
else
|
|
{
|
|
targetDirectory = filePath.substr(0, separator);
|
|
targetFilename = filePath.substr(separator + 1);
|
|
mainDirectoryLength = targetDirectory.length() + 1; // +1 includes trailing separator
|
|
}
|
|
|
|
if (targetFilename.length() == 0)
|
|
{
|
|
fprintf(stderr, _("Missing filename in %s\n"), filePath.c_str());
|
|
error();
|
|
}
|
|
|
|
// check filename for wildcards
|
|
hasWildcard = false;
|
|
if (targetFilename.find_first_of("*?") != string::npos)
|
|
hasWildcard = true;
|
|
|
|
// clear exclude hits vector
|
|
size_t excludeHitsVectorSize = excludeHitsVector.size();
|
|
for (size_t ix = 0; ix < excludeHitsVectorSize; ix++)
|
|
excludeHitsVector[ix] = false;
|
|
|
|
// If the filename is not quoted on Linux, bash will replace the
|
|
// wildcard instead of passing it to the program.
|
|
if (isRecursive && !hasWildcard)
|
|
{
|
|
fprintf(stderr, "%s\n", _("Recursive option with no wildcard"));
|
|
#ifndef _WIN32
|
|
fprintf(stderr, "%s\n", _("Did you intend quote the filename"));
|
|
#endif
|
|
error();
|
|
}
|
|
|
|
// display directory name for wildcard processing
|
|
if (hasWildcard)
|
|
{
|
|
printSeparatingLine();
|
|
printMsg(_("Directory %s\n"), targetDirectory + g_fileSeparator + targetFilename);
|
|
}
|
|
|
|
// create a vector of paths and file names to process
|
|
if (hasWildcard || isRecursive)
|
|
getFileNames(targetDirectory, targetFilename);
|
|
else
|
|
{
|
|
// verify a single file is not a directory (needed on Linux)
|
|
string entryFilepath = targetDirectory + g_fileSeparator + targetFilename;
|
|
struct stat statbuf;
|
|
if (stat(entryFilepath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
|
|
fileName.emplace_back(entryFilepath);
|
|
}
|
|
|
|
// check for unprocessed excludes
|
|
bool excludeErr = false;
|
|
for (size_t ix = 0; ix < excludeHitsVector.size(); ix++)
|
|
{
|
|
if (!excludeHitsVector[ix])
|
|
{
|
|
excludeErr = true;
|
|
if (!ignoreExcludeErrorsDisplay)
|
|
{
|
|
if (ignoreExcludeErrors)
|
|
printMsg(_("Exclude (unmatched) %s\n"), excludeVector[ix]);
|
|
else
|
|
fprintf(stderr, _("Exclude (unmatched) %s\n"), excludeVector[ix].c_str());
|
|
}
|
|
else
|
|
{
|
|
if (!ignoreExcludeErrors)
|
|
fprintf(stderr, _("Exclude (unmatched) %s\n"), excludeVector[ix].c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (excludeErr && !ignoreExcludeErrors)
|
|
{
|
|
if (hasWildcard && !isRecursive)
|
|
fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
|
|
error();
|
|
}
|
|
|
|
// check if files were found (probably an input error if not)
|
|
if (fileName.empty())
|
|
{
|
|
fprintf(stderr, _("No file to process %s\n"), filePath.c_str());
|
|
if (hasWildcard && !isRecursive)
|
|
fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
|
|
error();
|
|
}
|
|
|
|
if (hasWildcard)
|
|
printSeparatingLine();
|
|
}
|
|
|
|
bool ASConsole::fileNameVectorIsEmpty() const
|
|
{
|
|
return fileNameVector.empty();
|
|
}
|
|
|
|
bool ASConsole::isOption(const string& arg, const char* op)
|
|
{
|
|
return arg.compare(op) == 0;
|
|
}
|
|
|
|
bool ASConsole::isOption(const string& arg, const char* a, const char* b)
|
|
{
|
|
return (isOption(arg, a) || isOption(arg, b));
|
|
}
|
|
|
|
bool ASConsole::isParamOption(const string& arg, const char* option)
|
|
{
|
|
bool retVal = arg.compare(0, strlen(option), option) == 0;
|
|
// if comparing for short option, 2nd char of arg must be numeric
|
|
if (retVal && strlen(option) == 1 && arg.length() > 1)
|
|
if (!isdigit((unsigned char)arg[1]))
|
|
retVal = false;
|
|
return retVal;
|
|
}
|
|
|
|
// compare a path to the exclude vector
|
|
// used for both directories and filenames
|
|
// updates the g_excludeHitsVector
|
|
// return true if a match
|
|
bool ASConsole::isPathExclued(const string& subPath)
|
|
{
|
|
bool retVal = false;
|
|
|
|
// read the exclude vector checking for a match
|
|
for (size_t i = 0; i < excludeVector.size(); i++)
|
|
{
|
|
string exclude = excludeVector[i];
|
|
|
|
if (subPath.length() < exclude.length())
|
|
continue;
|
|
|
|
size_t compareStart = subPath.length() - exclude.length();
|
|
// subPath compare must start with a directory name
|
|
if (compareStart > 0)
|
|
{
|
|
char lastPathChar = subPath[compareStart - 1];
|
|
if (lastPathChar != g_fileSeparator)
|
|
continue;
|
|
}
|
|
|
|
string compare = subPath.substr(compareStart);
|
|
if (!g_isCaseSensitive)
|
|
{
|
|
// make it case insensitive for Windows
|
|
for (size_t j = 0; j < compare.length(); j++)
|
|
compare[j] = (char)tolower(compare[j]);
|
|
for (size_t j = 0; j < exclude.length(); j++)
|
|
exclude[j] = (char)tolower(exclude[j]);
|
|
}
|
|
// compare sub directory to exclude data - must check them all
|
|
if (compare == exclude)
|
|
{
|
|
excludeHitsVector[i] = true;
|
|
retVal = true;
|
|
break;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
void ASConsole::printHelp() const
|
|
{
|
|
cout << endl;
|
|
cout << " Artistic Style " << g_version << endl;
|
|
cout << " Maintained by: Jim Pattee\n";
|
|
cout << " Original Author: Tal Davidson\n";
|
|
cout << endl;
|
|
cout << "Usage:\n";
|
|
cout << "------\n";
|
|
cout << " astyle [OPTIONS] File1 File2 File3 [...]\n";
|
|
cout << endl;
|
|
cout << " astyle [OPTIONS] < Original > Beautified\n";
|
|
cout << endl;
|
|
cout << " When indenting a specific file, the resulting indented file RETAINS\n";
|
|
cout << " the original file-name. The original pre-indented file is renamed,\n";
|
|
cout << " with a suffix of \'.orig\' added to the original filename.\n";
|
|
cout << endl;
|
|
cout << " Wildcards (* and ?) may be used in the filename.\n";
|
|
cout << " A \'recursive\' option can process directories recursively.\n";
|
|
cout << endl;
|
|
cout << " By default, astyle is set up to indent with four spaces per indent,\n";
|
|
cout << " a maximal indentation of 40 spaces inside continuous statements,\n";
|
|
cout << " a minimum indentation of eight spaces inside conditional statements,\n";
|
|
cout << " and NO formatting options.\n";
|
|
cout << endl;
|
|
cout << "Options:\n";
|
|
cout << "--------\n";
|
|
cout << " This program follows the usual GNU command line syntax.\n";
|
|
cout << " Long options (starting with '--') must be written one at a time.\n";
|
|
cout << " Short options (starting with '-') may be appended together.\n";
|
|
cout << " Thus, -bps4 is the same as -b -p -s4.\n";
|
|
cout << endl;
|
|
cout << "Options File:\n";
|
|
cout << "-------------\n";
|
|
cout << " Artistic Style looks for a default options file in the\n";
|
|
cout << " following order:\n";
|
|
cout << " 1. The contents of the ARTISTIC_STYLE_OPTIONS environment\n";
|
|
cout << " variable if it exists.\n";
|
|
cout << " 2. The file called .astylerc in the directory pointed to by the\n";
|
|
cout << " HOME environment variable ( i.e. $HOME/.astylerc ).\n";
|
|
cout << " 3. The file called astylerc in the directory pointed to by the\n";
|
|
cout << " USERPROFILE environment variable (i.e. %USERPROFILE%\\astylerc).\n";
|
|
cout << " If a default options file is found, the options in this file will\n";
|
|
cout << " be parsed BEFORE the command-line options.\n";
|
|
cout << " Long options within the default option file may be written without\n";
|
|
cout << " the preliminary '--'.\n";
|
|
cout << endl;
|
|
cout << "Disable Formatting:\n";
|
|
cout << "-------------------\n";
|
|
cout << " Disable Block\n";
|
|
cout << " Blocks of code can be disabled with the comment tags *INDENT-OFF*\n";
|
|
cout << " and *INDENT-ON*. It must be contained in a one-line comment.\n";
|
|
cout << endl;
|
|
cout << " Disable Line\n";
|
|
cout << " Padding of operators can be disabled on a single line using the\n";
|
|
cout << " comment tag *NOPAD*. It must be contained in a line-end comment.\n";
|
|
cout << endl;
|
|
cout << "Brace Style Options:\n";
|
|
cout << "--------------------\n";
|
|
cout << " default brace style\n";
|
|
cout << " If no brace style is requested, the opening braces will not be\n";
|
|
cout << " changed and closing braces will be broken from the preceding line.\n";
|
|
cout << endl;
|
|
cout << " --style=allman OR --style=bsd OR --style=break OR -A1\n";
|
|
cout << " Allman style formatting/indenting.\n";
|
|
cout << " Broken braces.\n";
|
|
cout << endl;
|
|
cout << " --style=java OR --style=attach OR -A2\n";
|
|
cout << " Java style formatting/indenting.\n";
|
|
cout << " Attached braces.\n";
|
|
cout << endl;
|
|
cout << " --style=kr OR --style=k&r OR --style=k/r OR -A3\n";
|
|
cout << " Kernighan & Ritchie style formatting/indenting.\n";
|
|
cout << " Linux braces.\n";
|
|
cout << endl;
|
|
cout << " --style=stroustrup OR -A4\n";
|
|
cout << " Stroustrup style formatting/indenting.\n";
|
|
cout << " Linux braces.\n";
|
|
cout << endl;
|
|
cout << " --style=whitesmith OR -A5\n";
|
|
cout << " Whitesmith style formatting/indenting.\n";
|
|
cout << " Broken, indented braces.\n";
|
|
cout << " Indented class blocks and switch blocks.\n";
|
|
cout << endl;
|
|
cout << " --style=vtk OR -A15\n";
|
|
cout << " VTK style formatting/indenting.\n";
|
|
cout << " Broken, indented braces except for the opening braces.\n";
|
|
cout << endl;
|
|
cout << " --style=banner OR -A6\n";
|
|
cout << " Banner style formatting/indenting.\n";
|
|
cout << " Attached, indented braces.\n";
|
|
cout << endl;
|
|
cout << " --style=gnu OR -A7\n";
|
|
cout << " GNU style formatting/indenting.\n";
|
|
cout << " Broken braces, indented blocks.\n";
|
|
cout << endl;
|
|
cout << " --style=linux OR --style=knf OR -A8\n";
|
|
cout << " Linux style formatting/indenting.\n";
|
|
cout << " Linux braces, minimum conditional indent is one-half indent.\n";
|
|
cout << endl;
|
|
cout << " --style=horstmann OR --style=run-in OR -A9\n";
|
|
cout << " Horstmann style formatting/indenting.\n";
|
|
cout << " Run-in braces, indented switches.\n";
|
|
cout << endl;
|
|
cout << " --style=1tbs OR --style=otbs OR -A10\n";
|
|
cout << " One True Brace Style formatting/indenting.\n";
|
|
cout << " Linux braces, add braces to all conditionals.\n";
|
|
cout << endl;
|
|
cout << " --style=google OR -A14\n";
|
|
cout << " Google style formatting/indenting.\n";
|
|
cout << " Attached braces, indented class modifiers.\n";
|
|
cout << endl;
|
|
cout << " --style=mozilla OR -A16\n";
|
|
cout << " Mozilla style formatting/indenting.\n";
|
|
cout << " Linux braces, with broken braces for structs and enums,\n";
|
|
cout << " and attached braces for namespaces.\n";
|
|
cout << endl;
|
|
cout << " --style=pico OR -A11\n";
|
|
cout << " Pico style formatting/indenting.\n";
|
|
cout << " Run-in opening braces and attached closing braces.\n";
|
|
cout << " Uses keep one line blocks and keep one line statements.\n";
|
|
cout << endl;
|
|
cout << " --style=lisp OR -A12\n";
|
|
cout << " Lisp style formatting/indenting.\n";
|
|
cout << " Attached opening braces and attached closing braces.\n";
|
|
cout << " Uses keep one line statements.\n";
|
|
cout << endl;
|
|
cout << "Tab Options:\n";
|
|
cout << "------------\n";
|
|
cout << " default indent option\n";
|
|
cout << " If no indentation option is set, the default\n";
|
|
cout << " option of 4 spaces per indent will be used.\n";
|
|
cout << endl;
|
|
cout << " --indent=spaces=# OR -s#\n";
|
|
cout << " Indent using # spaces per indent. Not specifying #\n";
|
|
cout << " will result in a default of 4 spaces per indent.\n";
|
|
cout << endl;
|
|
cout << " --indent=tab OR --indent=tab=# OR -t OR -t#\n";
|
|
cout << " Indent using tab characters, assuming that each\n";
|
|
cout << " indent is # spaces long. Not specifying # will result\n";
|
|
cout << " in a default assumption of 4 spaces per indent.\n";
|
|
cout << endl;
|
|
cout << " --indent=force-tab=# OR -T#\n";
|
|
cout << " Indent using tab characters, assuming that each\n";
|
|
cout << " indent is # spaces long. Force tabs to be used in areas\n";
|
|
cout << " AStyle would prefer to use spaces.\n";
|
|
cout << endl;
|
|
cout << " --indent=force-tab-x=# OR -xT#\n";
|
|
cout << " Allows the tab length to be set to a length that is different\n";
|
|
cout << " from the indent length. This may cause the indentation to be\n";
|
|
cout << " a mix of both spaces and tabs. This option sets the tab length.\n";
|
|
cout << endl;
|
|
cout << "Brace Modify Options:\n";
|
|
cout << "---------------------\n";
|
|
cout << " --attach-namespaces OR -xn\n";
|
|
cout << " Attach braces to a namespace statement.\n";
|
|
cout << endl;
|
|
cout << " --attach-classes OR -xc\n";
|
|
cout << " Attach braces to a class statement.\n";
|
|
cout << endl;
|
|
cout << " --attach-inlines OR -xl\n";
|
|
cout << " Attach braces to class inline function definitions.\n";
|
|
cout << endl;
|
|
cout << " --attach-extern-c OR -xk\n";
|
|
cout << " Attach braces to an extern \"C\" statement.\n";
|
|
cout << endl;
|
|
cout << " --attach-closing-while OR -xV\n";
|
|
cout << " Attach closing while of do-while to the closing brace.\n";
|
|
cout << endl;
|
|
cout << "Indentation Options:\n";
|
|
cout << "--------------------\n";
|
|
cout << " --indent-classes OR -C\n";
|
|
cout << " Indent 'class' blocks so that the entire block is indented.\n";
|
|
cout << endl;
|
|
cout << " --indent-modifiers OR -xG\n";
|
|
cout << " Indent 'class' access modifiers, 'public:', 'protected:' or\n";
|
|
cout << " 'private:', one half indent. The rest of the class is not\n";
|
|
cout << " indented. \n";
|
|
cout << endl;
|
|
cout << " --indent-switches OR -S\n";
|
|
cout << " Indent 'switch' blocks, so that the inner 'case XXX:'\n";
|
|
cout << " headers are indented in relation to the switch block.\n";
|
|
cout << endl;
|
|
cout << " --indent-cases OR -K\n";
|
|
cout << " Indent case blocks from the 'case XXX:' headers.\n";
|
|
cout << " Case statements not enclosed in blocks are NOT indented.\n";
|
|
cout << endl;
|
|
cout << " --indent-namespaces OR -N\n";
|
|
cout << " Indent the contents of namespace blocks.\n";
|
|
cout << endl;
|
|
cout << " --indent-after-parens OR -xU\n";
|
|
cout << " Indent, instead of align, continuation lines following lines\n";
|
|
cout << " that contain an opening paren '(' or an assignment '='. \n";
|
|
cout << endl;
|
|
cout << " --indent-continuation=# OR -xt#\n";
|
|
cout << " Indent continuation lines an additional # indents.\n";
|
|
cout << " The valid values are 0 thru 4 indents.\n";
|
|
cout << " The default value is 1 indent.\n";
|
|
cout << endl;
|
|
cout << " --indent-labels OR -L\n";
|
|
cout << " Indent labels so that they appear one indent less than\n";
|
|
cout << " the current indentation level, rather than being\n";
|
|
cout << " flushed completely to the left (which is the default).\n";
|
|
cout << endl;
|
|
cout << " --indent-preproc-block OR -xW\n";
|
|
cout << " Indent preprocessor blocks at brace level 0.\n";
|
|
cout << " Without this option the preprocessor block is not indented.\n";
|
|
cout << endl;
|
|
cout << " --indent-preproc-cond OR -xw\n";
|
|
cout << " Indent preprocessor conditional statements #if/#else/#endif\n";
|
|
cout << " to the same level as the source code.\n";
|
|
cout << endl;
|
|
cout << " --indent-preproc-define OR -w\n";
|
|
cout << " Indent multi-line preprocessor #define statements.\n";
|
|
cout << endl;
|
|
cout << " --indent-col1-comments OR -Y\n";
|
|
cout << " Indent line comments that start in column one.\n";
|
|
cout << endl;
|
|
cout << " --min-conditional-indent=# OR -m#\n";
|
|
cout << " Indent a minimal # spaces in a continuous conditional\n";
|
|
cout << " belonging to a conditional header.\n";
|
|
cout << " The valid values are:\n";
|
|
cout << " 0 - no minimal indent.\n";
|
|
cout << " 1 - indent at least one additional indent.\n";
|
|
cout << " 2 - indent at least two additional indents.\n";
|
|
cout << " 3 - indent at least one-half an additional indent.\n";
|
|
cout << " The default value is 2, two additional indents.\n";
|
|
cout << endl;
|
|
cout << " --max-continuation-indent=# OR -M#\n";
|
|
cout << " Indent a maximal # spaces in a continuation line,\n";
|
|
cout << " relative to the previous line.\n";
|
|
cout << " The valid values are 40 thru 120.\n";
|
|
cout << " The default value is 40.\n";
|
|
cout << endl;
|
|
cout << "Padding Options:\n";
|
|
cout << "----------------\n";
|
|
cout << " --break-blocks OR -f\n";
|
|
cout << " Insert empty lines around unrelated blocks, labels, classes, ...\n";
|
|
cout << endl;
|
|
cout << " --break-blocks=all OR -F\n";
|
|
cout << " Like --break-blocks, except also insert empty lines \n";
|
|
cout << " around closing headers (e.g. 'else', 'catch', ...).\n";
|
|
cout << endl;
|
|
cout << " --pad-oper OR -p\n";
|
|
cout << " Insert space padding around operators.\n";
|
|
cout << endl;
|
|
cout << " --pad-comma OR -xg\n";
|
|
cout << " Insert space padding after commas.\n";
|
|
cout << endl;
|
|
cout << " --pad-paren OR -P\n";
|
|
cout << " Insert space padding around parenthesis on both the outside\n";
|
|
cout << " and the inside.\n";
|
|
cout << endl;
|
|
cout << " --pad-paren-out OR -d\n";
|
|
cout << " Insert space padding around parenthesis on the outside only.\n";
|
|
cout << endl;
|
|
cout << " --pad-first-paren-out OR -xd\n";
|
|
cout << " Insert space padding around first parenthesis in a series on\n";
|
|
cout << " the outside only.\n";
|
|
cout << endl;
|
|
cout << " --pad-paren-in OR -D\n";
|
|
cout << " Insert space padding around parenthesis on the inside only.\n";
|
|
cout << endl;
|
|
cout << " --pad-header OR -H\n";
|
|
cout << " Insert space padding after paren headers (e.g. 'if', 'for'...).\n";
|
|
cout << endl;
|
|
cout << " --unpad-paren OR -U\n";
|
|
cout << " Remove unnecessary space padding around parenthesis. This\n";
|
|
cout << " can be used in combination with the 'pad' options above.\n";
|
|
cout << endl;
|
|
cout << " --delete-empty-lines OR -xd\n";
|
|
cout << " Delete empty lines within a function or method.\n";
|
|
cout << " It will NOT delete lines added by the break-blocks options.\n";
|
|
cout << endl;
|
|
cout << " --fill-empty-lines OR -E\n";
|
|
cout << " Fill empty lines with the white space of their\n";
|
|
cout << " previous lines.\n";
|
|
cout << endl;
|
|
cout << " --align-pointer=type OR -k1\n";
|
|
cout << " --align-pointer=middle OR -k2\n";
|
|
cout << " --align-pointer=name OR -k3\n";
|
|
cout << " Attach a pointer or reference operator (*, &, or ^) to either\n";
|
|
cout << " the operator type (left), middle, or operator name (right).\n";
|
|
cout << " To align the reference separately use --align-reference.\n";
|
|
cout << endl;
|
|
cout << " --align-reference=none OR -W0\n";
|
|
cout << " --align-reference=type OR -W1\n";
|
|
cout << " --align-reference=middle OR -W2\n";
|
|
cout << " --align-reference=name OR -W3\n";
|
|
cout << " Attach a reference operator (&) to either\n";
|
|
cout << " the operator type (left), middle, or operator name (right).\n";
|
|
cout << " If not set, follow pointer alignment.\n";
|
|
cout << endl;
|
|
cout << "Formatting Options:\n";
|
|
cout << "-------------------\n";
|
|
cout << " --break-closing-braces OR -y\n";
|
|
cout << " Break braces before closing headers (e.g. 'else', 'catch', ...).\n";
|
|
cout << " Use with --style=java, --style=kr, --style=stroustrup,\n";
|
|
cout << " --style=linux, or --style=1tbs.\n";
|
|
cout << endl;
|
|
cout << " --break-elseifs OR -e\n";
|
|
cout << " Break 'else if()' statements into two different lines.\n";
|
|
cout << endl;
|
|
cout << " --break-one-line-headers OR -xb\n";
|
|
cout << " Break one line headers (e.g. 'if', 'while', 'else', ...) from a\n";
|
|
cout << " statement residing on the same line.\n";
|
|
cout << endl;
|
|
cout << " --add-braces OR -j\n";
|
|
cout << " Add braces to unbraced one line conditional statements.\n";
|
|
cout << endl;
|
|
cout << " --add-one-line-braces OR -J\n";
|
|
cout << " Add one line braces to unbraced one line conditional\n";
|
|
cout << " statements.\n";
|
|
cout << endl;
|
|
cout << " --remove-braces OR -xj\n";
|
|
cout << " Remove braces from a braced one line conditional statements.\n";
|
|
cout << endl;
|
|
cout << " --keep-one-line-blocks OR -O\n";
|
|
cout << " Don't break blocks residing completely on one line.\n";
|
|
cout << endl;
|
|
cout << " --keep-one-line-statements OR -o\n";
|
|
cout << " Don't break lines containing multiple statements into\n";
|
|
cout << " multiple single-statement lines.\n";
|
|
cout << endl;
|
|
cout << " --convert-tabs OR -c\n";
|
|
cout << " Convert tabs to the appropriate number of spaces.\n";
|
|
cout << endl;
|
|
cout << " --close-templates OR -xy\n";
|
|
cout << " Close ending angle brackets on template definitions.\n";
|
|
cout << endl;
|
|
cout << " --remove-comment-prefix OR -xp\n";
|
|
cout << " Remove the leading '*' prefix on multi-line comments and\n";
|
|
cout << " indent the comment text one indent.\n";
|
|
cout << endl;
|
|
cout << " --max-code-length=# OR -xC#\n";
|
|
cout << " --break-after-logical OR -xL\n";
|
|
cout << " max-code-length=# will break the line if it exceeds more than\n";
|
|
cout << " # characters. The valid values are 50 thru 200.\n";
|
|
cout << " If the line contains logical conditionals they will be placed\n";
|
|
cout << " first on the new line. The option break-after-logical will\n";
|
|
cout << " cause the logical conditional to be placed last on the\n";
|
|
cout << " previous line.\n";
|
|
cout << endl;
|
|
cout << " --mode=c\n";
|
|
cout << " Indent a C or C++ source file (this is the default).\n";
|
|
cout << endl;
|
|
cout << " --mode=java\n";
|
|
cout << " Indent a Java source file.\n";
|
|
cout << endl;
|
|
cout << " --mode=cs\n";
|
|
cout << " Indent a C# source file.\n";
|
|
cout << endl;
|
|
cout << "Objective-C Options:\n";
|
|
cout << "--------------------\n";
|
|
cout << " --pad-method-prefix OR -xQ\n";
|
|
cout << " Insert space padding after the '-' or '+' Objective-C\n";
|
|
cout << " method prefix.\n";
|
|
cout << endl;
|
|
cout << " --unpad-method-prefix OR -xR\n";
|
|
cout << " Remove all space padding after the '-' or '+' Objective-C\n";
|
|
cout << " method prefix.\n";
|
|
cout << endl;
|
|
cout << " --pad-return-type OR -xq\n";
|
|
cout << " Insert space padding after the Objective-C return type.\n";
|
|
cout << endl;
|
|
cout << " --unpad-return-type OR -xr\n";
|
|
cout << " Remove all space padding after the Objective-C return type.\n";
|
|
cout << endl;
|
|
cout << " --pad-param-type OR -xS\n";
|
|
cout << " Insert space padding after the Objective-C return type.\n";
|
|
cout << endl;
|
|
cout << " --unpad-param-type OR -xs\n";
|
|
cout << " Remove all space padding after the Objective-C return type.\n";
|
|
cout << endl;
|
|
cout << " --align-method-colon OR -xM\n";
|
|
cout << " Align the colons in an Objective-C method definition.\n";
|
|
cout << endl;
|
|
cout << " --pad-method-colon=none OR -xP\n";
|
|
cout << " --pad-method-colon=all OR -xP1\n";
|
|
cout << " --pad-method-colon=after OR -xP2\n";
|
|
cout << " --pad-method-colon=before OR -xP3\n";
|
|
cout << " Add or remove space padding before or after the colons in an\n";
|
|
cout << " Objective-C method call.\n";
|
|
cout << endl;
|
|
cout << "Other Options:\n";
|
|
cout << "--------------\n";
|
|
cout << " --suffix=####\n";
|
|
cout << " Append the suffix #### instead of '.orig' to original filename.\n";
|
|
cout << endl;
|
|
cout << " --suffix=none OR -n\n";
|
|
cout << " Do not retain a backup of the original file.\n";
|
|
cout << endl;
|
|
cout << " --recursive OR -r OR -R\n";
|
|
cout << " Process subdirectories recursively.\n";
|
|
cout << endl;
|
|
cout << " --dry-run\n";
|
|
cout << " Perform a trial run with no changes made to check for formatting.\n";
|
|
cout << endl;
|
|
cout << " --exclude=####\n";
|
|
cout << " Specify a file or directory #### to be excluded from processing.\n";
|
|
cout << endl;
|
|
cout << " --ignore-exclude-errors OR -i\n";
|
|
cout << " Allow processing to continue if there are errors in the exclude=####\n";
|
|
cout << " options. It will display the unmatched excludes.\n";
|
|
cout << endl;
|
|
cout << " --ignore-exclude-errors-x OR -xi\n";
|
|
cout << " Allow processing to continue if there are errors in the exclude=####\n";
|
|
cout << " options. It will NOT display the unmatched excludes.\n";
|
|
cout << endl;
|
|
cout << " --errors-to-stdout OR -X\n";
|
|
cout << " Print errors and help information to standard-output rather than\n";
|
|
cout << " to standard-error.\n";
|
|
cout << endl;
|
|
cout << " --preserve-date OR -Z\n";
|
|
cout << " Preserve the original file's date and time modified. The time\n";
|
|
cout << " modified will be changed a few micro seconds to force a compile.\n";
|
|
cout << endl;
|
|
cout << " --verbose OR -v\n";
|
|
cout << " Verbose mode. Extra informational messages will be displayed.\n";
|
|
cout << endl;
|
|
cout << " --formatted OR -Q\n";
|
|
cout << " Formatted display mode. Display only the files that have been\n";
|
|
cout << " formatted.\n";
|
|
cout << endl;
|
|
cout << " --quiet OR -q\n";
|
|
cout << " Quiet mode. Suppress all output except error messages.\n";
|
|
cout << endl;
|
|
cout << " --lineend=windows OR -z1\n";
|
|
cout << " --lineend=linux OR -z2\n";
|
|
cout << " --lineend=macold OR -z3\n";
|
|
cout << " Force use of the specified line end style. Valid options\n";
|
|
cout << " are windows (CRLF), linux (LF), and macold (CR).\n";
|
|
cout << endl;
|
|
cout << "Command Line Only:\n";
|
|
cout << "------------------\n";
|
|
cout << " --options=####\n";
|
|
cout << " Specify an options file #### to read and use.\n";
|
|
cout << endl;
|
|
cout << " --options=none\n";
|
|
cout << " Disable the default options file.\n";
|
|
cout << " Only the command-line parameters will be used.\n";
|
|
cout << endl;
|
|
cout << " --ascii OR -I\n";
|
|
cout << " The displayed output will be ascii characters only.\n";
|
|
cout << endl;
|
|
cout << " --version OR -V\n";
|
|
cout << " Print version number.\n";
|
|
cout << endl;
|
|
cout << " --help OR -h OR -?\n";
|
|
cout << " Print this help message.\n";
|
|
cout << endl;
|
|
cout << " --html OR -!\n";
|
|
cout << " Open the HTML help file \"astyle.html\" in the default browser.\n";
|
|
cout << " The documentation must be installed in the standard install path.\n";
|
|
cout << endl;
|
|
cout << " --html=####\n";
|
|
cout << " Open a HTML help file in the default browser using the file path\n";
|
|
cout << " ####. The path may include a directory path and a file name, or a\n";
|
|
cout << " file name only. Paths containing spaces must be enclosed in quotes.\n";
|
|
cout << endl;
|
|
cout << endl;
|
|
}
|
|
|
|
/**
|
|
* Process files in the fileNameVector.
|
|
*/
|
|
void ASConsole::processFiles()
|
|
{
|
|
if (isVerbose)
|
|
printVerboseHeader();
|
|
|
|
clock_t startTime = clock(); // start time of file formatting
|
|
|
|
// loop thru input fileNameVector and process the files
|
|
for (size_t i = 0; i < fileNameVector.size(); i++)
|
|
{
|
|
getFilePaths(fileNameVector[i]);
|
|
|
|
// loop thru fileName vector formatting the files
|
|
for (size_t j = 0; j < fileName.size(); j++)
|
|
formatFile(fileName[j]);
|
|
}
|
|
|
|
// files are processed, display stats
|
|
if (isVerbose)
|
|
printVerboseStats(startTime);
|
|
}
|
|
|
|
// process options from the command line and options file
|
|
// build the vectors fileNameVector, excludeVector, optionsVector, and fileOptionsVector
|
|
void ASConsole::processOptions(const vector<string>& argvOptions)
|
|
{
|
|
string arg;
|
|
bool ok = true;
|
|
bool shouldParseOptionsFile = true;
|
|
|
|
// get command line options
|
|
for (size_t i = 0; i < argvOptions.size(); i++)
|
|
{
|
|
arg = argvOptions[i];
|
|
|
|
if ( isOption(arg, "-I" )
|
|
|| isOption(arg, "--ascii") )
|
|
{
|
|
useAscii = true;
|
|
setlocale(LC_ALL, "C"); // use English decimal indicator
|
|
localizer.setLanguageFromName("en");
|
|
}
|
|
else if ( isOption(arg, "--options=none") )
|
|
{
|
|
shouldParseOptionsFile = false;
|
|
}
|
|
else if ( isParamOption(arg, "--options=") )
|
|
{
|
|
optionsFileName = getParam(arg, "--options=");
|
|
optionsFileRequired = true;
|
|
if (optionsFileName.empty())
|
|
setOptionsFileName(" ");
|
|
}
|
|
else if ( isOption(arg, "-h")
|
|
|| isOption(arg, "--help")
|
|
|| isOption(arg, "-?") )
|
|
{
|
|
printHelp();
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
else if ( isOption(arg, "-!")
|
|
|| isOption(arg, "--html") )
|
|
{
|
|
launchDefaultBrowser();
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
else if ( isParamOption(arg, "--html=") )
|
|
{
|
|
string htmlFilePath = getParam(arg, "--html=");
|
|
launchDefaultBrowser(htmlFilePath.c_str());
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
else if ( isOption(arg, "-V" )
|
|
|| isOption(arg, "--version") )
|
|
{
|
|
printf("Artistic Style Version %s\n", g_version);
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
else if (arg[0] == '-')
|
|
{
|
|
optionsVector.emplace_back(arg);
|
|
}
|
|
else // file-name
|
|
{
|
|
standardizePath(arg);
|
|
fileNameVector.emplace_back(arg);
|
|
}
|
|
}
|
|
|
|
// get options file path and name
|
|
if (shouldParseOptionsFile)
|
|
{
|
|
if (optionsFileName.empty())
|
|
{
|
|
char* env = getenv("ARTISTIC_STYLE_OPTIONS");
|
|
if (env != nullptr)
|
|
setOptionsFileName(env);
|
|
}
|
|
if (optionsFileName.empty())
|
|
{
|
|
char* env = getenv("HOME");
|
|
if (env != nullptr)
|
|
setOptionsFileName(string(env) + "/.astylerc");
|
|
}
|
|
if (optionsFileName.empty())
|
|
{
|
|
char* env = getenv("USERPROFILE");
|
|
if (env != nullptr)
|
|
setOptionsFileName(string(env) + "/astylerc");
|
|
}
|
|
if (!optionsFileName.empty())
|
|
standardizePath(optionsFileName);
|
|
}
|
|
|
|
// create the options file vector and parse the options for errors
|
|
ASOptions options(formatter, *this);
|
|
if (!optionsFileName.empty())
|
|
{
|
|
ifstream optionsIn(optionsFileName.c_str());
|
|
if (optionsIn)
|
|
{
|
|
options.importOptions(optionsIn, fileOptionsVector);
|
|
ok = options.parseOptions(fileOptionsVector,
|
|
string(_("Invalid option file options:")));
|
|
}
|
|
else
|
|
{
|
|
if (optionsFileRequired)
|
|
error(_("Cannot open options file"), optionsFileName.c_str());
|
|
optionsFileName.clear();
|
|
}
|
|
optionsIn.close();
|
|
}
|
|
if (!ok)
|
|
{
|
|
(*errorStream) << options.getOptionErrors() << endl;
|
|
(*errorStream) << _("For help on options type 'astyle -h'") << endl;
|
|
error();
|
|
}
|
|
|
|
// parse the command line options vector for errors
|
|
ok = options.parseOptions(optionsVector,
|
|
string(_("Invalid command line options:")));
|
|
if (!ok)
|
|
{
|
|
(*errorStream) << options.getOptionErrors() << endl;
|
|
(*errorStream) << _("For help on options type 'astyle -h'") << endl;
|
|
error();
|
|
}
|
|
}
|
|
|
|
// remove a file and check for an error
|
|
void ASConsole::removeFile(const char* fileName_, const char* errMsg) const
|
|
{
|
|
if (remove(fileName_) != 0)
|
|
{
|
|
if (errno == ENOENT) // no file is OK
|
|
errno = 0;
|
|
if (errno)
|
|
{
|
|
perror("errno message");
|
|
error(errMsg, fileName_);
|
|
}
|
|
}
|
|
}
|
|
|
|
// rename a file and check for an error
|
|
void ASConsole::renameFile(const char* oldFileName, const char* newFileName, const char* errMsg) const
|
|
{
|
|
int result = rename(oldFileName, newFileName);
|
|
if (result != 0)
|
|
{
|
|
// if file still exists the remove needs more time - retry
|
|
if (errno == EEXIST)
|
|
{
|
|
errno = 0;
|
|
waitForRemove(newFileName);
|
|
result = rename(oldFileName, newFileName);
|
|
}
|
|
if (result != 0)
|
|
{
|
|
perror("errno message");
|
|
error(errMsg, oldFileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// make sure file separators are correct type (Windows or Linux)
|
|
// remove ending file separator
|
|
// remove beginning file separator if requested and NOT a complete file path
|
|
void ASConsole::standardizePath(string& path, bool removeBeginningSeparator /*false*/) const
|
|
{
|
|
#ifdef __VMS
|
|
struct FAB fab;
|
|
struct NAML naml;
|
|
char less[NAML$C_MAXRSS];
|
|
char sess[NAM$C_MAXRSS];
|
|
int r0_status;
|
|
|
|
// If we are on a VMS system, translate VMS style filenames to unix
|
|
// style.
|
|
fab = cc$rms_fab;
|
|
fab.fab$l_fna = (char*) -1; // *NOPAD*
|
|
fab.fab$b_fns = 0;
|
|
fab.fab$l_naml = &naml;
|
|
naml = cc$rms_naml;
|
|
strcpy(sess, path.c_str());
|
|
naml.naml$l_long_filename = (char*)sess;
|
|
naml.naml$l_long_filename_size = path.length();
|
|
naml.naml$l_long_expand = less;
|
|
naml.naml$l_long_expand_alloc = sizeof(less);
|
|
naml.naml$l_esa = sess;
|
|
naml.naml$b_ess = sizeof(sess);
|
|
naml.naml$v_no_short_upcase = 1;
|
|
r0_status = sys$parse(&fab);
|
|
if (r0_status == RMS$_SYN)
|
|
{
|
|
error("File syntax error", path.c_str());
|
|
}
|
|
else
|
|
{
|
|
if (!$VMS_STATUS_SUCCESS(r0_status))
|
|
{
|
|
(void)lib$signal (r0_status);
|
|
}
|
|
}
|
|
less[naml.naml$l_long_expand_size - naml.naml$b_ver] = '\0';
|
|
sess[naml.naml$b_esl - naml.naml$b_ver] = '\0';
|
|
if (naml.naml$l_long_expand_size > naml.naml$b_esl)
|
|
{
|
|
path = decc$translate_vms (less);
|
|
}
|
|
else
|
|
{
|
|
path = decc$translate_vms(sess);
|
|
}
|
|
#endif /* __VMS */
|
|
|
|
// make sure separators are correct type (Windows or Linux)
|
|
for (size_t i = 0; i < path.length(); i++)
|
|
{
|
|
i = path.find_first_of("/\\", i);
|
|
if (i == string::npos)
|
|
break;
|
|
path[i] = g_fileSeparator;
|
|
}
|
|
// remove beginning separator if requested
|
|
if (removeBeginningSeparator && (path[0] == g_fileSeparator))
|
|
path.erase(0, 1);
|
|
}
|
|
|
|
void ASConsole::printMsg(const char* msg, const string& data) const
|
|
{
|
|
if (isQuiet)
|
|
return;
|
|
printf(msg, data.c_str());
|
|
}
|
|
|
|
void ASConsole::printSeparatingLine() const
|
|
{
|
|
string line;
|
|
for (size_t i = 0; i < 60; i++)
|
|
line.append("-");
|
|
printMsg("%s\n", line);
|
|
}
|
|
|
|
void ASConsole::printVerboseHeader() const
|
|
{
|
|
assert(isVerbose);
|
|
if (isQuiet)
|
|
return;
|
|
// get the date
|
|
time_t lt;
|
|
char str[20];
|
|
lt = time(nullptr);
|
|
struct tm* ptr = localtime(<);
|
|
strftime(str, 20, "%x", ptr);
|
|
// print the header
|
|
// 60 is the length of the separator in printSeparatingLine()
|
|
string header = "Artistic Style " + string(g_version);
|
|
size_t numSpaces = 60 - header.length() - strlen(str);
|
|
header.append(numSpaces, ' ');
|
|
header.append(str);
|
|
header.append("\n");
|
|
printf("%s", header.c_str());
|
|
// print options file
|
|
if (!optionsFileName.empty())
|
|
printf(_("Using default options file %s\n"), optionsFileName.c_str());
|
|
}
|
|
|
|
void ASConsole::printVerboseStats(clock_t startTime) const
|
|
{
|
|
assert(isVerbose);
|
|
if (isQuiet)
|
|
return;
|
|
if (hasWildcard)
|
|
printSeparatingLine();
|
|
string formatted = getNumberFormat(filesFormatted);
|
|
string unchanged = getNumberFormat(filesUnchanged);
|
|
printf(_(" %s formatted %s unchanged "), formatted.c_str(), unchanged.c_str());
|
|
|
|
// show processing time
|
|
clock_t stopTime = clock();
|
|
double secs = (stopTime - startTime) / double (CLOCKS_PER_SEC);
|
|
if (secs < 60)
|
|
{
|
|
if (secs < 2.0)
|
|
printf("%.2f", secs);
|
|
else if (secs < 20.0)
|
|
printf("%.1f", secs);
|
|
else
|
|
printf("%.0f", secs);
|
|
printf("%s", _(" seconds "));
|
|
}
|
|
else
|
|
{
|
|
// show minutes and seconds if time is greater than one minute
|
|
int min = (int) secs / 60;
|
|
secs -= min * 60;
|
|
int minsec = int (secs + .5);
|
|
printf(_("%d min %d sec "), min, minsec);
|
|
}
|
|
|
|
string lines = getNumberFormat(linesOut);
|
|
printf(_("%s lines\n"), lines.c_str());
|
|
}
|
|
|
|
void ASConsole::sleep(int seconds) const
|
|
{
|
|
clock_t endwait;
|
|
endwait = clock_t (clock () + seconds * CLOCKS_PER_SEC);
|
|
while (clock() < endwait) {}
|
|
}
|
|
|
|
bool ASConsole::stringEndsWith(const string& str, const string& suffix) const
|
|
{
|
|
int strIndex = (int) str.length() - 1;
|
|
int suffixIndex = (int) suffix.length() - 1;
|
|
|
|
while (strIndex >= 0 && suffixIndex >= 0)
|
|
{
|
|
if (tolower(str[strIndex]) != tolower(suffix[suffixIndex]))
|
|
return false;
|
|
|
|
--strIndex;
|
|
--suffixIndex;
|
|
}
|
|
// suffix longer than string
|
|
if (strIndex < 0 && suffixIndex >= 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void ASConsole::updateExcludeVector(const string& suffixParam)
|
|
{
|
|
excludeVector.emplace_back(suffixParam);
|
|
standardizePath(excludeVector.back(), true);
|
|
excludeHitsVector.push_back(false);
|
|
}
|
|
|
|
int ASConsole::waitForRemove(const char* newFileName) const
|
|
{
|
|
struct stat stBuf;
|
|
int seconds;
|
|
// sleep a max of 20 seconds for the remove
|
|
for (seconds = 1; seconds <= 20; seconds++)
|
|
{
|
|
sleep(1);
|
|
if (stat(newFileName, &stBuf) != 0)
|
|
break;
|
|
}
|
|
errno = 0;
|
|
return seconds;
|
|
}
|
|
|
|
// From The Code Project http://www.codeproject.com/string/wildcmp.asp
|
|
// Written by Jack Handy - jakkhandy@hotmail.com
|
|
// Modified to compare case insensitive for Windows
|
|
int ASConsole::wildcmp(const char* wild, const char* data) const
|
|
{
|
|
const char* cp = nullptr, *mp = nullptr;
|
|
bool cmpval;
|
|
|
|
while ((*data) && (*wild != '*'))
|
|
{
|
|
if (!g_isCaseSensitive)
|
|
cmpval = (tolower(*wild) != tolower(*data)) && (*wild != '?');
|
|
else
|
|
cmpval = (*wild != *data) && (*wild != '?');
|
|
|
|
if (cmpval)
|
|
{
|
|
return 0;
|
|
}
|
|
wild++;
|
|
data++;
|
|
}
|
|
|
|
while (*data)
|
|
{
|
|
if (*wild == '*')
|
|
{
|
|
if (!*++wild)
|
|
{
|
|
return 1;
|
|
}
|
|
mp = wild;
|
|
cp = data + 1;
|
|
}
|
|
else
|
|
{
|
|
if (!g_isCaseSensitive)
|
|
cmpval = (tolower(*wild) == tolower(*data) || (*wild == '?'));
|
|
else
|
|
cmpval = (*wild == *data) || (*wild == '?');
|
|
|
|
if (cmpval)
|
|
{
|
|
wild++;
|
|
data++;
|
|
}
|
|
else
|
|
{
|
|
wild = mp;
|
|
data = cp++;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (*wild == '*')
|
|
{
|
|
wild++;
|
|
}
|
|
return !*wild;
|
|
}
|
|
|
|
void ASConsole::writeFile(const string& fileName_, FileEncoding encoding, ostringstream& out) const
|
|
{
|
|
// save date accessed and date modified of original file
|
|
struct stat stBuf;
|
|
bool statErr = false;
|
|
if (stat(fileName_.c_str(), &stBuf) == -1)
|
|
statErr = true;
|
|
|
|
// create a backup
|
|
if (!noBackup)
|
|
{
|
|
string origFileName = fileName_ + origSuffix;
|
|
removeFile(origFileName.c_str(), "Cannot remove pre-existing backup file");
|
|
renameFile(fileName_.c_str(), origFileName.c_str(), "Cannot create backup file");
|
|
}
|
|
|
|
// write the output file
|
|
ofstream fout(fileName_.c_str(), ios::binary | ios::trunc);
|
|
if (!fout)
|
|
error("Cannot open output file", fileName_.c_str());
|
|
if (encoding == UTF_16LE || encoding == UTF_16BE)
|
|
{
|
|
// convert utf-8 to utf-16
|
|
bool isBigEndian = (encoding == UTF_16BE);
|
|
size_t utf16Size = utf8_16.utf16LengthFromUtf8(out.str().c_str(), out.str().length());
|
|
char* utf16Out = new char[utf16Size];
|
|
size_t utf16Len = utf8_16.utf8ToUtf16(const_cast<char*>(out.str().c_str()),
|
|
out.str().length(), isBigEndian, utf16Out);
|
|
assert(utf16Len == utf16Size);
|
|
fout << string(utf16Out, utf16Len);
|
|
delete[] utf16Out;
|
|
}
|
|
else
|
|
fout << out.str();
|
|
|
|
fout.close();
|
|
|
|
// change date modified to original file date
|
|
// Embarcadero must be linked with cw32mt not cw32
|
|
if (preserveDate)
|
|
{
|
|
if (!statErr)
|
|
{
|
|
struct utimbuf outBuf;
|
|
outBuf.actime = stBuf.st_atime;
|
|
// add ticks so 'make' will recognize a change
|
|
// Visual Studio 2008 needs more than 1
|
|
outBuf.modtime = stBuf.st_mtime + 10;
|
|
if (utime(fileName_.c_str(), &outBuf) == -1)
|
|
statErr = true;
|
|
}
|
|
if (statErr)
|
|
{
|
|
perror("errno message");
|
|
(*errorStream) << "********* Cannot preserve file date" << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
#else // ASTYLE_LIB
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ASLibrary class
|
|
// used by shared object (DLL) calls
|
|
//-----------------------------------------------------------------------------
|
|
|
|
utf16_t* ASLibrary::formatUtf16(const utf16_t* pSourceIn, // the source to be formatted
|
|
const utf16_t* pOptions, // AStyle options
|
|
fpError fpErrorHandler, // error handler function
|
|
fpAlloc fpMemoryAlloc) const // memory allocation function)
|
|
{
|
|
const char* utf8In = convertUtf16ToUtf8(pSourceIn);
|
|
if (utf8In == nullptr)
|
|
{
|
|
fpErrorHandler(121, "Cannot convert input utf-16 to utf-8.");
|
|
return nullptr;
|
|
}
|
|
const char* utf8Options = convertUtf16ToUtf8(pOptions);
|
|
if (utf8Options == nullptr)
|
|
{
|
|
delete[] utf8In;
|
|
fpErrorHandler(122, "Cannot convert options utf-16 to utf-8.");
|
|
return nullptr;
|
|
}
|
|
// call the Artistic Style formatting function
|
|
// cannot use the callers memory allocation here
|
|
char* utf8Out = AStyleMain(utf8In,
|
|
utf8Options,
|
|
fpErrorHandler,
|
|
ASLibrary::tempMemoryAllocation);
|
|
// finished with these
|
|
delete[] utf8In;
|
|
delete[] utf8Options;
|
|
utf8In = nullptr;
|
|
utf8Options = nullptr;
|
|
// AStyle error has already been sent
|
|
if (utf8Out == nullptr)
|
|
return nullptr;
|
|
// convert text to wide char and return it
|
|
utf16_t* utf16Out = convertUtf8ToUtf16(utf8Out, fpMemoryAlloc);
|
|
delete[] utf8Out;
|
|
utf8Out = nullptr;
|
|
if (utf16Out == nullptr)
|
|
{
|
|
fpErrorHandler(123, "Cannot convert output utf-8 to utf-16.");
|
|
return nullptr;
|
|
}
|
|
return utf16Out;
|
|
}
|
|
|
|
// STATIC method to allocate temporary memory for AStyle formatting.
|
|
// The data will be converted before being returned to the calling program.
|
|
char* STDCALL ASLibrary::tempMemoryAllocation(unsigned long memoryNeeded)
|
|
{
|
|
char* buffer = new (nothrow) char[memoryNeeded];
|
|
return buffer;
|
|
}
|
|
|
|
/**
|
|
* Convert utf-8 strings to utf16 strings.
|
|
* Memory is allocated by the calling program memory allocation function.
|
|
* The calling function must check for errors.
|
|
*/
|
|
utf16_t* ASLibrary::convertUtf8ToUtf16(const char* utf8In, fpAlloc fpMemoryAlloc) const
|
|
{
|
|
if (utf8In == nullptr)
|
|
return nullptr;
|
|
char* data = const_cast<char*>(utf8In);
|
|
size_t dataSize = strlen(utf8In);
|
|
bool isBigEndian = utf8_16.getBigEndian();
|
|
// return size is in number of CHARs, not utf16_t
|
|
size_t utf16Size = (utf8_16.utf16LengthFromUtf8(data, dataSize) + sizeof(utf16_t));
|
|
char* utf16Out = fpMemoryAlloc((long)utf16Size);
|
|
if (utf16Out == nullptr)
|
|
return nullptr;
|
|
#ifdef NDEBUG
|
|
utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
|
|
#else
|
|
size_t utf16Len = utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
|
|
assert(utf16Len == utf16Size);
|
|
#endif
|
|
assert(utf16Size == (utf8_16.utf16len(reinterpret_cast<utf16_t*>(utf16Out)) + 1) * sizeof(utf16_t));
|
|
return reinterpret_cast<utf16_t*>(utf16Out);
|
|
}
|
|
|
|
/**
|
|
* Convert utf16 strings to utf-8.
|
|
* The calling function must check for errors and delete the
|
|
* allocated memory.
|
|
*/
|
|
char* ASLibrary::convertUtf16ToUtf8(const utf16_t* utf16In) const
|
|
{
|
|
if (utf16In == nullptr)
|
|
return nullptr;
|
|
char* data = reinterpret_cast<char*>(const_cast<utf16_t*>(utf16In));
|
|
// size must be in chars
|
|
size_t dataSize = utf8_16.utf16len(utf16In) * sizeof(utf16_t);
|
|
bool isBigEndian = utf8_16.getBigEndian();
|
|
size_t utf8Size = utf8_16.utf8LengthFromUtf16(data, dataSize, isBigEndian) + 1;
|
|
char* utf8Out = new (nothrow) char[utf8Size];
|
|
if (utf8Out == nullptr)
|
|
return nullptr;
|
|
#ifdef NDEBUG
|
|
utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
|
|
#else
|
|
size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
|
|
assert(utf8Len == utf8Size);
|
|
#endif
|
|
assert(utf8Size == strlen(utf8Out) + 1);
|
|
return utf8Out;
|
|
}
|
|
|
|
#endif // ASTYLE_LIB
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// ASOptions class
|
|
// used by both console and library builds
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifdef ASTYLE_LIB
|
|
ASOptions::ASOptions(ASFormatter& formatterArg)
|
|
: formatter(formatterArg)
|
|
{ }
|
|
#else
|
|
ASOptions::ASOptions(ASFormatter& formatterArg, ASConsole& consoleArg)
|
|
: formatter(formatterArg), console(consoleArg)
|
|
{ }
|
|
#endif
|
|
|
|
/**
|
|
* parse the options vector
|
|
* optionsVector can be either a fileOptionsVector (options file) or an optionsVector (command line)
|
|
*
|
|
* @return true if no errors, false if errors
|
|
*/
|
|
bool ASOptions::parseOptions(vector<string>& optionsVector, const string& errorInfo)
|
|
{
|
|
vector<string>::iterator option;
|
|
string arg, subArg;
|
|
optionErrors.clear();
|
|
|
|
for (option = optionsVector.begin(); option != optionsVector.end(); ++option)
|
|
{
|
|
arg = *option;
|
|
|
|
if (arg.compare(0, 2, "--") == 0)
|
|
parseOption(arg.substr(2), errorInfo);
|
|
else if (arg[0] == '-')
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 1; i < arg.length(); ++i)
|
|
{
|
|
if (i > 1
|
|
&& isalpha((unsigned char)arg[i])
|
|
&& arg[i - 1] != 'x')
|
|
{
|
|
// parse the previous option in subArg
|
|
parseOption(subArg, errorInfo);
|
|
subArg = "";
|
|
}
|
|
// append the current option to subArg
|
|
subArg.append(1, arg[i]);
|
|
}
|
|
// parse the last option
|
|
parseOption(subArg, errorInfo);
|
|
subArg = "";
|
|
}
|
|
else
|
|
{
|
|
parseOption(arg, errorInfo);
|
|
subArg = "";
|
|
}
|
|
}
|
|
if (optionErrors.str().length() > 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
void ASOptions::parseOption(const string& arg, const string& errorInfo)
|
|
{
|
|
if ( isOption(arg, "style=allman") || isOption(arg, "style=bsd") || isOption(arg, "style=break") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_ALLMAN);
|
|
}
|
|
else if ( isOption(arg, "style=java") || isOption(arg, "style=attach") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_JAVA);
|
|
}
|
|
else if ( isOption(arg, "style=k&r") || isOption(arg, "style=kr") || isOption(arg, "style=k/r") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_KR);
|
|
}
|
|
else if ( isOption(arg, "style=stroustrup") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_STROUSTRUP);
|
|
}
|
|
else if ( isOption(arg, "style=whitesmith") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_WHITESMITH);
|
|
}
|
|
else if ( isOption(arg, "style=vtk") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_VTK);
|
|
}
|
|
else if ( isOption(arg, "style=banner") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_BANNER);
|
|
}
|
|
else if ( isOption(arg, "style=gnu") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_GNU);
|
|
}
|
|
else if ( isOption(arg, "style=linux") || isOption(arg, "style=knf") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_LINUX);
|
|
}
|
|
else if ( isOption(arg, "style=horstmann") || isOption(arg, "style=run-in") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_HORSTMANN);
|
|
}
|
|
else if ( isOption(arg, "style=1tbs") || isOption(arg, "style=otbs") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_1TBS);
|
|
}
|
|
else if ( isOption(arg, "style=google") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_GOOGLE);
|
|
}
|
|
else if (isOption(arg, "style=mozilla"))
|
|
{
|
|
formatter.setFormattingStyle(STYLE_MOZILLA);
|
|
}
|
|
else if ( isOption(arg, "style=pico") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_PICO);
|
|
}
|
|
else if ( isOption(arg, "style=lisp") || isOption(arg, "style=python") )
|
|
{
|
|
formatter.setFormattingStyle(STYLE_LISP);
|
|
}
|
|
else if ( isParamOption(arg, "A") )
|
|
{
|
|
int style = 0;
|
|
string styleParam = getParam(arg, "A");
|
|
if (styleParam.length() > 0)
|
|
style = atoi(styleParam.c_str());
|
|
if (style == 1)
|
|
formatter.setFormattingStyle(STYLE_ALLMAN);
|
|
else if (style == 2)
|
|
formatter.setFormattingStyle(STYLE_JAVA);
|
|
else if (style == 3)
|
|
formatter.setFormattingStyle(STYLE_KR);
|
|
else if (style == 4)
|
|
formatter.setFormattingStyle(STYLE_STROUSTRUP);
|
|
else if (style == 5)
|
|
formatter.setFormattingStyle(STYLE_WHITESMITH);
|
|
else if (style == 6)
|
|
formatter.setFormattingStyle(STYLE_BANNER);
|
|
else if (style == 7)
|
|
formatter.setFormattingStyle(STYLE_GNU);
|
|
else if (style == 8)
|
|
formatter.setFormattingStyle(STYLE_LINUX);
|
|
else if (style == 9)
|
|
formatter.setFormattingStyle(STYLE_HORSTMANN);
|
|
else if (style == 10)
|
|
formatter.setFormattingStyle(STYLE_1TBS);
|
|
else if (style == 11)
|
|
formatter.setFormattingStyle(STYLE_PICO);
|
|
else if (style == 12)
|
|
formatter.setFormattingStyle(STYLE_LISP);
|
|
else if (style == 14)
|
|
formatter.setFormattingStyle(STYLE_GOOGLE);
|
|
else if (style == 15)
|
|
formatter.setFormattingStyle(STYLE_VTK);
|
|
else if (style == 16)
|
|
formatter.setFormattingStyle(STYLE_MOZILLA);
|
|
else
|
|
isOptionError(arg, errorInfo);
|
|
}
|
|
// must check for mode=cs before mode=c !!!
|
|
else if ( isOption(arg, "mode=cs") )
|
|
{
|
|
formatter.setSharpStyle();
|
|
formatter.setModeManuallySet(true);
|
|
}
|
|
else if ( isOption(arg, "mode=c") )
|
|
{
|
|
formatter.setCStyle();
|
|
formatter.setModeManuallySet(true);
|
|
}
|
|
else if ( isOption(arg, "mode=java") )
|
|
{
|
|
formatter.setJavaStyle();
|
|
formatter.setModeManuallySet(true);
|
|
}
|
|
else if ( isParamOption(arg, "t", "indent=tab=") )
|
|
{
|
|
int spaceNum = 4;
|
|
string spaceNumParam = getParam(arg, "t", "indent=tab=");
|
|
if (spaceNumParam.length() > 0)
|
|
spaceNum = atoi(spaceNumParam.c_str());
|
|
if (spaceNum < 2 || spaceNum > 20)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
{
|
|
formatter.setTabIndentation(spaceNum, false);
|
|
}
|
|
}
|
|
else if ( isOption(arg, "indent=tab") )
|
|
{
|
|
formatter.setTabIndentation(4);
|
|
}
|
|
else if ( isParamOption(arg, "T", "indent=force-tab=") )
|
|
{
|
|
int spaceNum = 4;
|
|
string spaceNumParam = getParam(arg, "T", "indent=force-tab=");
|
|
if (spaceNumParam.length() > 0)
|
|
spaceNum = atoi(spaceNumParam.c_str());
|
|
if (spaceNum < 2 || spaceNum > 20)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
{
|
|
formatter.setTabIndentation(spaceNum, true);
|
|
}
|
|
}
|
|
else if ( isOption(arg, "indent=force-tab") )
|
|
{
|
|
formatter.setTabIndentation(4, true);
|
|
}
|
|
else if ( isParamOption(arg, "xT", "indent=force-tab-x=") )
|
|
{
|
|
int tabNum = 8;
|
|
string tabNumParam = getParam(arg, "xT", "indent=force-tab-x=");
|
|
if (tabNumParam.length() > 0)
|
|
tabNum = atoi(tabNumParam.c_str());
|
|
if (tabNum < 2 || tabNum > 20)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
{
|
|
formatter.setForceTabXIndentation(tabNum);
|
|
}
|
|
}
|
|
else if ( isOption(arg, "indent=force-tab-x") )
|
|
{
|
|
formatter.setForceTabXIndentation(8);
|
|
}
|
|
else if ( isParamOption(arg, "s", "indent=spaces=") )
|
|
{
|
|
int spaceNum = 4;
|
|
string spaceNumParam = getParam(arg, "s", "indent=spaces=");
|
|
if (spaceNumParam.length() > 0)
|
|
spaceNum = atoi(spaceNumParam.c_str());
|
|
if (spaceNum < 2 || spaceNum > 20)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
{
|
|
formatter.setSpaceIndentation(spaceNum);
|
|
}
|
|
}
|
|
else if ( isOption(arg, "indent=spaces") )
|
|
{
|
|
formatter.setSpaceIndentation(4);
|
|
}
|
|
else if (isParamOption(arg, "xt", "indent-continuation="))
|
|
{
|
|
int contIndent = 1;
|
|
string contIndentParam = getParam(arg, "xt", "indent-continuation=");
|
|
if (contIndentParam.length() > 0)
|
|
contIndent = atoi(contIndentParam.c_str());
|
|
if (contIndent < 0)
|
|
isOptionError(arg, errorInfo);
|
|
else if (contIndent > 4)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
formatter.setContinuationIndentation(contIndent);
|
|
}
|
|
else if ( isParamOption(arg, "m", "min-conditional-indent=") )
|
|
{
|
|
int minIndent = MINCOND_TWO;
|
|
string minIndentParam = getParam(arg, "m", "min-conditional-indent=");
|
|
if (minIndentParam.length() > 0)
|
|
minIndent = atoi(minIndentParam.c_str());
|
|
if (minIndent >= MINCOND_END)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
formatter.setMinConditionalIndentOption(minIndent);
|
|
}
|
|
else if ( isParamOption(arg, "M", "max-continuation-indent=") )
|
|
{
|
|
int maxIndent = 40;
|
|
string maxIndentParam = getParam(arg, "M", "max-continuation-indent=");
|
|
if (maxIndentParam.length() > 0)
|
|
maxIndent = atoi(maxIndentParam.c_str());
|
|
if (maxIndent < 40)
|
|
isOptionError(arg, errorInfo);
|
|
else if (maxIndent > 120)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
formatter.setMaxContinuationIndentLength(maxIndent);
|
|
}
|
|
else if ( isOption(arg, "N", "indent-namespaces") )
|
|
{
|
|
formatter.setNamespaceIndent(true);
|
|
}
|
|
else if ( isOption(arg, "C", "indent-classes") )
|
|
{
|
|
formatter.setClassIndent(true);
|
|
}
|
|
else if ( isOption(arg, "xG", "indent-modifiers") )
|
|
{
|
|
formatter.setModifierIndent(true);
|
|
}
|
|
else if ( isOption(arg, "S", "indent-switches") )
|
|
{
|
|
formatter.setSwitchIndent(true);
|
|
}
|
|
else if ( isOption(arg, "K", "indent-cases") )
|
|
{
|
|
formatter.setCaseIndent(true);
|
|
}
|
|
else if ( isOption(arg, "xU", "indent-after-parens") )
|
|
{
|
|
formatter.setAfterParenIndent(true);
|
|
}
|
|
else if ( isOption(arg, "L", "indent-labels") )
|
|
{
|
|
formatter.setLabelIndent(true);
|
|
}
|
|
else if (isOption(arg, "xW", "indent-preproc-block"))
|
|
{
|
|
formatter.setPreprocBlockIndent(true);
|
|
}
|
|
else if ( isOption(arg, "w", "indent-preproc-define") )
|
|
{
|
|
formatter.setPreprocDefineIndent(true);
|
|
}
|
|
else if ( isOption(arg, "xw", "indent-preproc-cond") )
|
|
{
|
|
formatter.setPreprocConditionalIndent(true);
|
|
}
|
|
else if ( isOption(arg, "y", "break-closing-braces") )
|
|
{
|
|
formatter.setBreakClosingHeaderBracesMode(true);
|
|
}
|
|
else if ( isOption(arg, "O", "keep-one-line-blocks") )
|
|
{
|
|
formatter.setBreakOneLineBlocksMode(false);
|
|
}
|
|
else if ( isOption(arg, "o", "keep-one-line-statements") )
|
|
{
|
|
formatter.setBreakOneLineStatementsMode(false);
|
|
}
|
|
else if ( isOption(arg, "P", "pad-paren") )
|
|
{
|
|
formatter.setParensOutsidePaddingMode(true);
|
|
formatter.setParensInsidePaddingMode(true);
|
|
}
|
|
else if ( isOption(arg, "d", "pad-paren-out") )
|
|
{
|
|
formatter.setParensOutsidePaddingMode(true);
|
|
}
|
|
else if ( isOption(arg, "xd", "pad-first-paren-out") )
|
|
{
|
|
formatter.setParensFirstPaddingMode(true);
|
|
}
|
|
else if ( isOption(arg, "D", "pad-paren-in") )
|
|
{
|
|
formatter.setParensInsidePaddingMode(true);
|
|
}
|
|
else if ( isOption(arg, "H", "pad-header") )
|
|
{
|
|
formatter.setParensHeaderPaddingMode(true);
|
|
}
|
|
else if ( isOption(arg, "U", "unpad-paren") )
|
|
{
|
|
formatter.setParensUnPaddingMode(true);
|
|
}
|
|
else if ( isOption(arg, "p", "pad-oper") )
|
|
{
|
|
formatter.setOperatorPaddingMode(true);
|
|
}
|
|
else if (isOption(arg, "xg", "pad-comma"))
|
|
{
|
|
formatter.setCommaPaddingMode(true);
|
|
}
|
|
else if ( isOption(arg, "xe", "delete-empty-lines") )
|
|
{
|
|
formatter.setDeleteEmptyLinesMode(true);
|
|
}
|
|
else if ( isOption(arg, "E", "fill-empty-lines") )
|
|
{
|
|
formatter.setEmptyLineFill(true);
|
|
}
|
|
else if ( isOption(arg, "c", "convert-tabs") )
|
|
{
|
|
formatter.setTabSpaceConversionMode(true);
|
|
}
|
|
else if ( isOption(arg, "xy", "close-templates") )
|
|
{
|
|
formatter.setCloseTemplatesMode(true);
|
|
}
|
|
else if ( isOption(arg, "F", "break-blocks=all") )
|
|
{
|
|
formatter.setBreakBlocksMode(true);
|
|
formatter.setBreakClosingHeaderBlocksMode(true);
|
|
}
|
|
else if ( isOption(arg, "f", "break-blocks") )
|
|
{
|
|
formatter.setBreakBlocksMode(true);
|
|
}
|
|
else if ( isOption(arg, "e", "break-elseifs") )
|
|
{
|
|
formatter.setBreakElseIfsMode(true);
|
|
}
|
|
else if ( isOption(arg, "xb", "break-one-line-headers") )
|
|
{
|
|
formatter.setBreakOneLineHeadersMode(true);
|
|
}
|
|
else if ( isOption(arg, "j", "add-braces") )
|
|
{
|
|
formatter.setAddBracesMode(true);
|
|
}
|
|
else if ( isOption(arg, "J", "add-one-line-braces") )
|
|
{
|
|
formatter.setAddOneLineBracesMode(true);
|
|
}
|
|
else if ( isOption(arg, "xj", "remove-braces") )
|
|
{
|
|
formatter.setRemoveBracesMode(true);
|
|
}
|
|
else if ( isOption(arg, "Y", "indent-col1-comments") )
|
|
{
|
|
formatter.setIndentCol1CommentsMode(true);
|
|
}
|
|
else if ( isOption(arg, "align-pointer=type") )
|
|
{
|
|
formatter.setPointerAlignment(PTR_ALIGN_TYPE);
|
|
}
|
|
else if ( isOption(arg, "align-pointer=middle") )
|
|
{
|
|
formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
|
|
}
|
|
else if ( isOption(arg, "align-pointer=name") )
|
|
{
|
|
formatter.setPointerAlignment(PTR_ALIGN_NAME);
|
|
}
|
|
else if ( isParamOption(arg, "k") )
|
|
{
|
|
int align = 0;
|
|
string styleParam = getParam(arg, "k");
|
|
if (styleParam.length() > 0)
|
|
align = atoi(styleParam.c_str());
|
|
if (align < 1 || align > 3)
|
|
isOptionError(arg, errorInfo);
|
|
else if (align == 1)
|
|
formatter.setPointerAlignment(PTR_ALIGN_TYPE);
|
|
else if (align == 2)
|
|
formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
|
|
else if (align == 3)
|
|
formatter.setPointerAlignment(PTR_ALIGN_NAME);
|
|
}
|
|
else if ( isOption(arg, "align-reference=none") )
|
|
{
|
|
formatter.setReferenceAlignment(REF_ALIGN_NONE);
|
|
}
|
|
else if ( isOption(arg, "align-reference=type") )
|
|
{
|
|
formatter.setReferenceAlignment(REF_ALIGN_TYPE);
|
|
}
|
|
else if ( isOption(arg, "align-reference=middle") )
|
|
{
|
|
formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
|
|
}
|
|
else if ( isOption(arg, "align-reference=name") )
|
|
{
|
|
formatter.setReferenceAlignment(REF_ALIGN_NAME);
|
|
}
|
|
else if ( isParamOption(arg, "W") )
|
|
{
|
|
int align = 0;
|
|
string styleParam = getParam(arg, "W");
|
|
if (styleParam.length() > 0)
|
|
align = atoi(styleParam.c_str());
|
|
if (align < 0 || align > 3)
|
|
isOptionError(arg, errorInfo);
|
|
else if (align == 0)
|
|
formatter.setReferenceAlignment(REF_ALIGN_NONE);
|
|
else if (align == 1)
|
|
formatter.setReferenceAlignment(REF_ALIGN_TYPE);
|
|
else if (align == 2)
|
|
formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
|
|
else if (align == 3)
|
|
formatter.setReferenceAlignment(REF_ALIGN_NAME);
|
|
}
|
|
else if ( isParamOption(arg, "max-code-length=") )
|
|
{
|
|
int maxLength = 50;
|
|
string maxLengthParam = getParam(arg, "max-code-length=");
|
|
if (maxLengthParam.length() > 0)
|
|
maxLength = atoi(maxLengthParam.c_str());
|
|
if (maxLength < 50)
|
|
isOptionError(arg, errorInfo);
|
|
else if (maxLength > 200)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
formatter.setMaxCodeLength(maxLength);
|
|
}
|
|
else if ( isParamOption(arg, "xC") )
|
|
{
|
|
int maxLength = 50;
|
|
string maxLengthParam = getParam(arg, "xC");
|
|
if (maxLengthParam.length() > 0)
|
|
maxLength = atoi(maxLengthParam.c_str());
|
|
if (maxLength > 200)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
formatter.setMaxCodeLength(maxLength);
|
|
}
|
|
else if ( isOption(arg, "xL", "break-after-logical") )
|
|
{
|
|
formatter.setBreakAfterMode(true);
|
|
}
|
|
else if ( isOption(arg, "xc", "attach-classes") )
|
|
{
|
|
formatter.setAttachClass(true);
|
|
}
|
|
else if ( isOption(arg, "xV", "attach-closing-while") )
|
|
{
|
|
formatter.setAttachClosingWhile(true);
|
|
}
|
|
else if ( isOption(arg, "xk", "attach-extern-c") )
|
|
{
|
|
formatter.setAttachExternC(true);
|
|
}
|
|
else if ( isOption(arg, "xn", "attach-namespaces") )
|
|
{
|
|
formatter.setAttachNamespace(true);
|
|
}
|
|
else if ( isOption(arg, "xl", "attach-inlines") )
|
|
{
|
|
formatter.setAttachInline(true);
|
|
}
|
|
else if ( isOption(arg, "xp", "remove-comment-prefix") )
|
|
{
|
|
formatter.setStripCommentPrefix(true);
|
|
}
|
|
// Objective-C options
|
|
else if ( isOption(arg, "xQ", "pad-method-prefix") )
|
|
{
|
|
formatter.setMethodPrefixPaddingMode(true);
|
|
}
|
|
else if ( isOption(arg, "xR", "unpad-method-prefix") )
|
|
{
|
|
formatter.setMethodPrefixUnPaddingMode(true);
|
|
}
|
|
else if (isOption(arg, "xq", "pad-return-type"))
|
|
{
|
|
formatter.setReturnTypePaddingMode(true);
|
|
}
|
|
else if (isOption(arg, "xr", "unpad-return-type"))
|
|
{
|
|
formatter.setReturnTypeUnPaddingMode(true);
|
|
}
|
|
else if (isOption(arg, "xS", "pad-param-type"))
|
|
{
|
|
formatter.setParamTypePaddingMode(true);
|
|
}
|
|
else if (isOption(arg, "xs", "unpad-param-type"))
|
|
{
|
|
formatter.setParamTypeUnPaddingMode(true);
|
|
}
|
|
else if (isOption(arg, "xM", "align-method-colon"))
|
|
{
|
|
formatter.setAlignMethodColon(true);
|
|
}
|
|
else if ( isOption(arg, "xP0", "pad-method-colon=none") )
|
|
{
|
|
formatter.setObjCColonPaddingMode(COLON_PAD_NONE);
|
|
}
|
|
else if ( isOption(arg, "xP1", "pad-method-colon=all") )
|
|
{
|
|
formatter.setObjCColonPaddingMode(COLON_PAD_ALL);
|
|
}
|
|
else if ( isOption(arg, "xP2", "pad-method-colon=after") )
|
|
{
|
|
formatter.setObjCColonPaddingMode(COLON_PAD_AFTER);
|
|
}
|
|
else if ( isOption(arg, "xP3", "pad-method-colon=before") )
|
|
{
|
|
formatter.setObjCColonPaddingMode(COLON_PAD_BEFORE);
|
|
}
|
|
// depreciated options ////////////////////////////////////////////////////////////////////////
|
|
else if ( isOption(arg, "indent-preprocessor") ) // depreciated release 2.04
|
|
{
|
|
formatter.setPreprocDefineIndent(true);
|
|
}
|
|
else if ( isOption(arg, "style=ansi") ) // depreciated release 2.05
|
|
{
|
|
formatter.setFormattingStyle(STYLE_ALLMAN);
|
|
}
|
|
// depreciated in release 3.0 /////////////////////////////////////////////////////////////////
|
|
else if ( isOption(arg, "break-closing-brackets") ) // depreciated release 3.0
|
|
{
|
|
formatter.setBreakClosingHeaderBracketsMode(true);
|
|
}
|
|
else if ( isOption(arg, "add-brackets") ) // depreciated release 3.0
|
|
{
|
|
formatter.setAddBracketsMode(true);
|
|
}
|
|
else if ( isOption(arg, "add-one-line-brackets") ) // depreciated release 3.0
|
|
{
|
|
formatter.setAddOneLineBracketsMode(true);
|
|
}
|
|
else if ( isOption(arg, "remove-brackets") ) // depreciated release 3.0
|
|
{
|
|
formatter.setRemoveBracketsMode(true);
|
|
}
|
|
else if ( isParamOption(arg, "max-instatement-indent=") ) // depreciated release 3.0
|
|
{
|
|
int maxIndent = 40;
|
|
string maxIndentParam = getParam(arg, "max-instatement-indent=");
|
|
if (maxIndentParam.length() > 0)
|
|
maxIndent = atoi(maxIndentParam.c_str());
|
|
if (maxIndent < 40)
|
|
isOptionError(arg, errorInfo);
|
|
else if (maxIndent > 120)
|
|
isOptionError(arg, errorInfo);
|
|
else
|
|
formatter.setMaxInStatementIndentLength(maxIndent);
|
|
}
|
|
// NOTE: Removed in release 2.04.
|
|
// else if ( isOption(arg, "b", "brackets=break") )
|
|
// {
|
|
// formatter.setBracketFormatMode(BREAK_MODE);
|
|
// }
|
|
// else if ( isOption(arg, "a", "brackets=attach") )
|
|
// {
|
|
// formatter.setBracketFormatMode(ATTACH_MODE);
|
|
// }
|
|
// else if ( isOption(arg, "l", "brackets=linux") )
|
|
// {
|
|
// formatter.setBracketFormatMode(LINUX_MODE);
|
|
// }
|
|
// else if ( isOption(arg, "u", "brackets=stroustrup") )
|
|
// {
|
|
// formatter.setBracketFormatMode(STROUSTRUP_MODE);
|
|
// }
|
|
// else if ( isOption(arg, "g", "brackets=run-in") )
|
|
// {
|
|
// formatter.setBracketFormatMode(RUN_IN_MODE);
|
|
// }
|
|
// end depreciated options ////////////////////////////////////////////////////////////////////
|
|
#ifdef ASTYLE_LIB
|
|
// End of options used by GUI /////////////////////////////////////////////////////////////////
|
|
else
|
|
isOptionError(arg, errorInfo);
|
|
#else
|
|
// Options used by only console ///////////////////////////////////////////////////////////////
|
|
else if ( isOption(arg, "n", "suffix=none") )
|
|
{
|
|
console.setNoBackup(true);
|
|
}
|
|
else if ( isParamOption(arg, "suffix=") )
|
|
{
|
|
string suffixParam = getParam(arg, "suffix=");
|
|
if (suffixParam.length() > 0)
|
|
{
|
|
console.setOrigSuffix(suffixParam);
|
|
}
|
|
}
|
|
else if ( isParamOption(arg, "exclude=") )
|
|
{
|
|
string suffixParam = getParam(arg, "exclude=");
|
|
if (suffixParam.length() > 0)
|
|
console.updateExcludeVector(suffixParam);
|
|
}
|
|
else if ( isOption(arg, "r", "R") || isOption(arg, "recursive") )
|
|
{
|
|
console.setIsRecursive(true);
|
|
}
|
|
else if (isOption(arg, "dry-run"))
|
|
{
|
|
console.setIsDryRun(true);
|
|
}
|
|
else if ( isOption(arg, "Z", "preserve-date") )
|
|
{
|
|
console.setPreserveDate(true);
|
|
}
|
|
else if ( isOption(arg, "v", "verbose") )
|
|
{
|
|
console.setIsVerbose(true);
|
|
}
|
|
else if ( isOption(arg, "Q", "formatted") )
|
|
{
|
|
console.setIsFormattedOnly(true);
|
|
}
|
|
else if ( isOption(arg, "q", "quiet") )
|
|
{
|
|
console.setIsQuiet(true);
|
|
}
|
|
else if ( isOption(arg, "i", "ignore-exclude-errors") )
|
|
{
|
|
console.setIgnoreExcludeErrors(true);
|
|
}
|
|
else if ( isOption(arg, "xi", "ignore-exclude-errors-x") )
|
|
{
|
|
console.setIgnoreExcludeErrorsAndDisplay(true);
|
|
}
|
|
else if ( isOption(arg, "X", "errors-to-stdout") )
|
|
{
|
|
console.setErrorStream(&cout);
|
|
}
|
|
else if ( isOption(arg, "lineend=windows") )
|
|
{
|
|
formatter.setLineEndFormat(LINEEND_WINDOWS);
|
|
}
|
|
else if ( isOption(arg, "lineend=linux") )
|
|
{
|
|
formatter.setLineEndFormat(LINEEND_LINUX);
|
|
}
|
|
else if ( isOption(arg, "lineend=macold") )
|
|
{
|
|
formatter.setLineEndFormat(LINEEND_MACOLD);
|
|
}
|
|
else if ( isParamOption(arg, "z") )
|
|
{
|
|
int lineendType = 0;
|
|
string lineendParam = getParam(arg, "z");
|
|
if (lineendParam.length() > 0)
|
|
lineendType = atoi(lineendParam.c_str());
|
|
if (lineendType < 1 || lineendType > 3)
|
|
isOptionError(arg, errorInfo);
|
|
else if (lineendType == 1)
|
|
formatter.setLineEndFormat(LINEEND_WINDOWS);
|
|
else if (lineendType == 2)
|
|
formatter.setLineEndFormat(LINEEND_LINUX);
|
|
else if (lineendType == 3)
|
|
formatter.setLineEndFormat(LINEEND_MACOLD);
|
|
}
|
|
else if ( isParamOption(arg, "stdin=") )
|
|
{
|
|
string path = getParam(arg, "stdin=");
|
|
console.standardizePath(path);
|
|
console.setStdPathIn(path);
|
|
}
|
|
else if ( isParamOption(arg, "stdout=") )
|
|
{
|
|
string path = getParam(arg, "stdout=");
|
|
console.standardizePath(path);
|
|
console.setStdPathOut(path);
|
|
}
|
|
else
|
|
isOptionError(arg, errorInfo);
|
|
#endif
|
|
} // End of parseOption function
|
|
|
|
// Parse options from the options file.
|
|
void ASOptions::importOptions(istream& in, vector<string>& optionsVector)
|
|
{
|
|
char ch;
|
|
bool isInQuote = false;
|
|
char quoteChar = ' ';
|
|
string currentToken;
|
|
|
|
while (in)
|
|
{
|
|
currentToken = "";
|
|
do
|
|
{
|
|
in.get(ch);
|
|
if (in.eof())
|
|
break;
|
|
// treat '#' as line comments
|
|
if (ch == '#')
|
|
while (in)
|
|
{
|
|
in.get(ch);
|
|
if (ch == '\n' || ch == '\r')
|
|
break;
|
|
}
|
|
|
|
// break options on new-lines, tabs, commas, or spaces
|
|
// remove quotes from output
|
|
if (in.eof() || ch == '\n' || ch == '\r' || ch == '\t' || ch == ',')
|
|
break;
|
|
if (ch == ' ' && !isInQuote)
|
|
break;
|
|
if (ch == quoteChar && isInQuote)
|
|
break;
|
|
if (ch == '"' || ch == '\'')
|
|
{
|
|
isInQuote = true;
|
|
quoteChar = ch;
|
|
continue;
|
|
}
|
|
currentToken.append(1, ch);
|
|
}
|
|
while (in);
|
|
|
|
if (currentToken.length() != 0)
|
|
optionsVector.emplace_back(currentToken);
|
|
isInQuote = false;
|
|
}
|
|
}
|
|
|
|
string ASOptions::getOptionErrors() const
|
|
{
|
|
return optionErrors.str();
|
|
}
|
|
|
|
string ASOptions::getParam(const string& arg, const char* op)
|
|
{
|
|
return arg.substr(strlen(op));
|
|
}
|
|
|
|
string ASOptions::getParam(const string& arg, const char* op1, const char* op2)
|
|
{
|
|
return isParamOption(arg, op1) ? getParam(arg, op1) : getParam(arg, op2);
|
|
}
|
|
|
|
bool ASOptions::isOption(const string& arg, const char* op)
|
|
{
|
|
return arg.compare(op) == 0;
|
|
}
|
|
|
|
bool ASOptions::isOption(const string& arg, const char* op1, const char* op2)
|
|
{
|
|
return (isOption(arg, op1) || isOption(arg, op2));
|
|
}
|
|
|
|
void ASOptions::isOptionError(const string& arg, const string& errorInfo)
|
|
{
|
|
if (optionErrors.str().length() == 0)
|
|
optionErrors << errorInfo << endl; // need main error message
|
|
optionErrors << arg << endl;
|
|
}
|
|
|
|
bool ASOptions::isParamOption(const string& arg, const char* option)
|
|
{
|
|
bool retVal = arg.compare(0, strlen(option), option) == 0;
|
|
// if comparing for short option, 2nd char of arg must be numeric
|
|
if (retVal && strlen(option) == 1 && arg.length() > 1)
|
|
if (!isdigit((unsigned char)arg[1]))
|
|
retVal = false;
|
|
return retVal;
|
|
}
|
|
|
|
bool ASOptions::isParamOption(const string& arg, const char* option1, const char* option2)
|
|
{
|
|
return isParamOption(arg, option1) || isParamOption(arg, option2);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ASEncoding class
|
|
//----------------------------------------------------------------------------
|
|
|
|
// Return true if an int is big endian.
|
|
bool ASEncoding::getBigEndian() const
|
|
{
|
|
short int word = 0x0001;
|
|
char* byte = (char*) &word;
|
|
return (byte[0] ? false : true);
|
|
}
|
|
|
|
// Swap the two low order bytes of a 16 bit integer value.
|
|
int ASEncoding::swap16bit(int value) const
|
|
{
|
|
return ( ((value & 0xff) << 8) | ((value & 0xff00) >> 8) );
|
|
}
|
|
|
|
// Return the length of a utf-16 C string.
|
|
// The length is in number of utf16_t.
|
|
size_t ASEncoding::utf16len(const utf16* utf16In) const
|
|
{
|
|
size_t length = 0;
|
|
while (*utf16In++ != '\0')
|
|
length++;
|
|
return length;
|
|
}
|
|
|
|
// Adapted from SciTE UniConversion.cxx.
|
|
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
|
|
// Modified for Artistic Style by Jim Pattee.
|
|
// Compute the length of an output utf-8 file given a utf-16 file.
|
|
// Input inLen is the size in BYTES (not wchar_t).
|
|
size_t ASEncoding::utf8LengthFromUtf16(const char* utf16In, size_t inLen, bool isBigEndian) const
|
|
{
|
|
size_t len = 0;
|
|
size_t wcharLen = inLen / 2;
|
|
const short* uptr = reinterpret_cast<const short*>(utf16In);
|
|
for (size_t i = 0; i < wcharLen && uptr[i];)
|
|
{
|
|
size_t uch = isBigEndian ? swap16bit(uptr[i]) : uptr[i];
|
|
if (uch < 0x80)
|
|
len++;
|
|
else if (uch < 0x800)
|
|
len += 2;
|
|
else if ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_TRAIL_LAST))
|
|
{
|
|
len += 4;
|
|
i++;
|
|
}
|
|
else
|
|
len += 3;
|
|
i++;
|
|
}
|
|
return len;
|
|
}
|
|
|
|
// Adapted from SciTE Utf8_16.cxx.
|
|
// Copyright (C) 2002 Scott Kirkwood.
|
|
// Modified for Artistic Style by Jim Pattee.
|
|
// Convert a utf-8 file to utf-16.
|
|
size_t ASEncoding::utf8ToUtf16(char* utf8In, size_t inLen, bool isBigEndian, char* utf16Out) const
|
|
{
|
|
int nCur = 0;
|
|
ubyte* pRead = reinterpret_cast<ubyte*>(utf8In);
|
|
utf16* pCur = reinterpret_cast<utf16*>(utf16Out);
|
|
const ubyte* pEnd = pRead + inLen;
|
|
const utf16* pCurStart = pCur;
|
|
eState state = eStart;
|
|
|
|
// the BOM will automatically be converted to utf-16
|
|
while (pRead < pEnd)
|
|
{
|
|
switch (state)
|
|
{
|
|
case eStart:
|
|
if ((0xF0 & *pRead) == 0xF0)
|
|
{
|
|
nCur = (0x7 & *pRead) << 18;
|
|
state = eSecondOf4Bytes;
|
|
}
|
|
else if ((0xE0 & *pRead) == 0xE0)
|
|
{
|
|
nCur = (~0xE0 & *pRead) << 12;
|
|
state = ePenultimate;
|
|
}
|
|
else if ((0xC0 & *pRead) == 0xC0)
|
|
{
|
|
nCur = (~0xC0 & *pRead) << 6;
|
|
state = eFinal;
|
|
}
|
|
else
|
|
{
|
|
nCur = *pRead;
|
|
state = eStart;
|
|
}
|
|
break;
|
|
case eSecondOf4Bytes:
|
|
nCur |= (0x3F & *pRead) << 12;
|
|
state = ePenultimate;
|
|
break;
|
|
case ePenultimate:
|
|
nCur |= (0x3F & *pRead) << 6;
|
|
state = eFinal;
|
|
break;
|
|
case eFinal:
|
|
nCur |= (0x3F & *pRead);
|
|
state = eStart;
|
|
break;
|
|
// no default case is needed
|
|
}
|
|
++pRead;
|
|
|
|
if (state == eStart)
|
|
{
|
|
int codePoint = nCur;
|
|
if (codePoint >= SURROGATE_FIRST_VALUE)
|
|
{
|
|
codePoint -= SURROGATE_FIRST_VALUE;
|
|
int lead = (codePoint >> 10) + SURROGATE_LEAD_FIRST;
|
|
*pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(lead) : lead);
|
|
int trail = (codePoint & 0x3ff) + SURROGATE_TRAIL_FIRST;
|
|
*pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(trail) : trail);
|
|
}
|
|
else
|
|
*pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(codePoint) : codePoint);
|
|
}
|
|
}
|
|
// return value is the output length in BYTES (not wchar_t)
|
|
return (pCur - pCurStart) * 2;
|
|
}
|
|
|
|
// Adapted from SciTE UniConversion.cxx.
|
|
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
|
|
// Modified for Artistic Style by Jim Pattee.
|
|
// Compute the length of an output utf-16 file given a utf-8 file.
|
|
// Return value is the size in BYTES (not wchar_t).
|
|
size_t ASEncoding::utf16LengthFromUtf8(const char* utf8In, size_t len) const
|
|
{
|
|
size_t ulen = 0;
|
|
size_t charLen;
|
|
for (size_t i = 0; i < len;)
|
|
{
|
|
unsigned char ch = static_cast<unsigned char>(utf8In[i]);
|
|
if (ch < 0x80)
|
|
charLen = 1;
|
|
else if (ch < 0x80 + 0x40 + 0x20)
|
|
charLen = 2;
|
|
else if (ch < 0x80 + 0x40 + 0x20 + 0x10)
|
|
charLen = 3;
|
|
else
|
|
{
|
|
charLen = 4;
|
|
ulen++;
|
|
}
|
|
i += charLen;
|
|
ulen++;
|
|
}
|
|
// return value is the length in bytes (not wchar_t)
|
|
return ulen * 2;
|
|
}
|
|
|
|
// Adapted from SciTE Utf8_16.cxx.
|
|
// Copyright (C) 2002 Scott Kirkwood.
|
|
// Modified for Artistic Style by Jim Pattee.
|
|
// Convert a utf-16 file to utf-8.
|
|
size_t ASEncoding::utf16ToUtf8(char* utf16In, size_t inLen, bool isBigEndian,
|
|
bool firstBlock, char* utf8Out) const
|
|
{
|
|
int nCur16 = 0;
|
|
int nCur = 0;
|
|
ubyte* pRead = reinterpret_cast<ubyte*>(utf16In);
|
|
ubyte* pCur = reinterpret_cast<ubyte*>(utf8Out);
|
|
const ubyte* pEnd = pRead + inLen;
|
|
const ubyte* pCurStart = pCur;
|
|
static eState state = eStart; // state is retained for subsequent blocks
|
|
if (firstBlock)
|
|
state = eStart;
|
|
|
|
// the BOM will automatically be converted to utf-8
|
|
while (pRead < pEnd)
|
|
{
|
|
switch (state)
|
|
{
|
|
case eStart:
|
|
if (pRead >= pEnd)
|
|
{
|
|
++pRead;
|
|
break;
|
|
}
|
|
if (isBigEndian)
|
|
{
|
|
nCur16 = static_cast<utf16>(*pRead++ << 8);
|
|
nCur16 |= static_cast<utf16>(*pRead);
|
|
}
|
|
else
|
|
{
|
|
nCur16 = *pRead++;
|
|
nCur16 |= static_cast<utf16>(*pRead << 8);
|
|
}
|
|
if (nCur16 >= SURROGATE_LEAD_FIRST && nCur16 <= SURROGATE_LEAD_LAST)
|
|
{
|
|
++pRead;
|
|
int trail;
|
|
if (isBigEndian)
|
|
{
|
|
trail = static_cast<utf16>(*pRead++ << 8);
|
|
trail |= static_cast<utf16>(*pRead);
|
|
}
|
|
else
|
|
{
|
|
trail = *pRead++;
|
|
trail |= static_cast<utf16>(*pRead << 8);
|
|
}
|
|
nCur16 = (((nCur16 & 0x3ff) << 10) | (trail & 0x3ff)) + SURROGATE_FIRST_VALUE;
|
|
}
|
|
++pRead;
|
|
|
|
if (nCur16 < 0x80)
|
|
{
|
|
nCur = static_cast<ubyte>(nCur16 & 0xFF);
|
|
state = eStart;
|
|
}
|
|
else if (nCur16 < 0x800)
|
|
{
|
|
nCur = static_cast<ubyte>(0xC0 | (nCur16 >> 6));
|
|
state = eFinal;
|
|
}
|
|
else if (nCur16 < SURROGATE_FIRST_VALUE)
|
|
{
|
|
nCur = static_cast<ubyte>(0xE0 | (nCur16 >> 12));
|
|
state = ePenultimate;
|
|
}
|
|
else
|
|
{
|
|
nCur = static_cast<ubyte>(0xF0 | (nCur16 >> 18));
|
|
state = eSecondOf4Bytes;
|
|
}
|
|
break;
|
|
case eSecondOf4Bytes:
|
|
nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 12) & 0x3F));
|
|
state = ePenultimate;
|
|
break;
|
|
case ePenultimate:
|
|
nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 6) & 0x3F));
|
|
state = eFinal;
|
|
break;
|
|
case eFinal:
|
|
nCur = static_cast<ubyte>(0x80 | (nCur16 & 0x3F));
|
|
state = eStart;
|
|
break;
|
|
// no default case is needed
|
|
}
|
|
*pCur++ = static_cast<ubyte>(nCur);
|
|
}
|
|
return pCur - pCurStart;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
} // namespace astyle
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
using namespace astyle;
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ASTYLE_JNI functions for Java library builds
|
|
//----------------------------------------------------------------------------
|
|
|
|
#ifdef ASTYLE_JNI
|
|
|
|
// called by a java program to get the version number
|
|
// the function name is constructed from method names in the calling java program
|
|
extern "C" EXPORT
|
|
jstring STDCALL Java_AStyleInterface_AStyleGetVersion(JNIEnv* env, jclass)
|
|
{
|
|
return env->NewStringUTF(g_version);
|
|
}
|
|
|
|
// called by a java program to format the source code
|
|
// the function name is constructed from method names in the calling java program
|
|
extern "C" EXPORT
|
|
jstring STDCALL Java_AStyleInterface_AStyleMain(JNIEnv* env,
|
|
jobject obj,
|
|
jstring textInJava,
|
|
jstring optionsJava)
|
|
{
|
|
g_env = env; // make object available globally
|
|
g_obj = obj; // make object available globally
|
|
|
|
jstring textErr = env->NewStringUTF(""); // zero length text returned if an error occurs
|
|
|
|
// get the method ID
|
|
jclass cls = env->GetObjectClass(obj);
|
|
g_mid = env->GetMethodID(cls, "ErrorHandler", "(ILjava/lang/String;)V");
|
|
if (g_mid == nullptr)
|
|
{
|
|
cout << "Cannot find java method ErrorHandler" << endl;
|
|
return textErr;
|
|
}
|
|
|
|
// convert jstring to char*
|
|
const char* textIn = env->GetStringUTFChars(textInJava, nullptr);
|
|
const char* options = env->GetStringUTFChars(optionsJava, nullptr);
|
|
|
|
// call the C++ formatting function
|
|
char* textOut = AStyleMain(textIn, options, javaErrorHandler, javaMemoryAlloc);
|
|
// if an error message occurred it was displayed by errorHandler
|
|
if (textOut == nullptr)
|
|
return textErr;
|
|
|
|
// release memory
|
|
jstring textOutJava = env->NewStringUTF(textOut);
|
|
delete[] textOut;
|
|
env->ReleaseStringUTFChars(textInJava, textIn);
|
|
env->ReleaseStringUTFChars(optionsJava, options);
|
|
|
|
return textOutJava;
|
|
}
|
|
|
|
// Call the Java error handler
|
|
void STDCALL javaErrorHandler(int errorNumber, const char* errorMessage)
|
|
{
|
|
jstring errorMessageJava = g_env->NewStringUTF(errorMessage);
|
|
g_env->CallVoidMethod(g_obj, g_mid, errorNumber, errorMessageJava);
|
|
}
|
|
|
|
// Allocate memory for the formatted text
|
|
char* STDCALL javaMemoryAlloc(unsigned long memoryNeeded)
|
|
{
|
|
// error condition is checked after return from AStyleMain
|
|
char* buffer = new (nothrow) char[memoryNeeded];
|
|
return buffer;
|
|
}
|
|
|
|
#endif // ASTYLE_JNI
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ASTYLE_LIB functions for library builds
|
|
//----------------------------------------------------------------------------
|
|
|
|
#ifdef ASTYLE_LIB
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ASTYLE_LIB entry point for AStyleMainUtf16 library builds
|
|
//----------------------------------------------------------------------------
|
|
/*
|
|
* IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
|
|
* /EXPORT:AStyleMain=_AStyleMain@16
|
|
* /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
|
|
* /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
|
|
* No /EXPORT is required for x64
|
|
*/
|
|
extern "C" EXPORT utf16_t* STDCALL AStyleMainUtf16(const utf16_t* pSourceIn, // the source to be formatted
|
|
const utf16_t* pOptions, // AStyle options
|
|
fpError fpErrorHandler, // error handler function
|
|
fpAlloc fpMemoryAlloc) // memory allocation function
|
|
{
|
|
if (fpErrorHandler == nullptr) // cannot display a message if no error handler
|
|
return nullptr;
|
|
|
|
if (pSourceIn == nullptr)
|
|
{
|
|
fpErrorHandler(101, "No pointer to source input.");
|
|
return nullptr;
|
|
}
|
|
if (pOptions == nullptr)
|
|
{
|
|
fpErrorHandler(102, "No pointer to AStyle options.");
|
|
return nullptr;
|
|
}
|
|
if (fpMemoryAlloc == nullptr)
|
|
{
|
|
fpErrorHandler(103, "No pointer to memory allocation function.");
|
|
return nullptr;
|
|
}
|
|
#ifndef _WIN32
|
|
// check size of utf16_t on Linux
|
|
int sizeCheck = 2;
|
|
if (sizeof(utf16_t) != sizeCheck)
|
|
{
|
|
fpErrorHandler(104, "Unsigned short is not the correct size.");
|
|
return nullptr;
|
|
}
|
|
#endif
|
|
|
|
ASLibrary library;
|
|
utf16_t* utf16Out = library.formatUtf16(pSourceIn, pOptions, fpErrorHandler, fpMemoryAlloc);
|
|
return utf16Out;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ASTYLE_LIB entry point for library builds
|
|
//----------------------------------------------------------------------------
|
|
/*
|
|
* IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
|
|
* /EXPORT:AStyleMain=_AStyleMain@16
|
|
* /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
|
|
* /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
|
|
* No /EXPORT is required for x64
|
|
*/
|
|
extern "C" EXPORT char* STDCALL AStyleMain(const char* pSourceIn, // the source to be formatted
|
|
const char* pOptions, // AStyle options
|
|
fpError fpErrorHandler, // error handler function
|
|
fpAlloc fpMemoryAlloc) // memory allocation function
|
|
{
|
|
if (fpErrorHandler == nullptr) // cannot display a message if no error handler
|
|
return nullptr;
|
|
|
|
if (pSourceIn == nullptr)
|
|
{
|
|
fpErrorHandler(101, "No pointer to source input.");
|
|
return nullptr;
|
|
}
|
|
if (pOptions == nullptr)
|
|
{
|
|
fpErrorHandler(102, "No pointer to AStyle options.");
|
|
return nullptr;
|
|
}
|
|
if (fpMemoryAlloc == nullptr)
|
|
{
|
|
fpErrorHandler(103, "No pointer to memory allocation function.");
|
|
return nullptr;
|
|
}
|
|
|
|
ASFormatter formatter;
|
|
ASOptions options(formatter);
|
|
|
|
vector<string> optionsVector;
|
|
istringstream opt(pOptions);
|
|
|
|
options.importOptions(opt, optionsVector);
|
|
|
|
bool ok = options.parseOptions(optionsVector, "Invalid Artistic Style options:");
|
|
if (!ok)
|
|
fpErrorHandler(130, options.getOptionErrors().c_str());
|
|
|
|
istringstream in(pSourceIn);
|
|
ASStreamIterator<istringstream> streamIterator(&in);
|
|
ostringstream out;
|
|
formatter.init(&streamIterator);
|
|
|
|
while (formatter.hasMoreLines())
|
|
{
|
|
out << formatter.nextLine();
|
|
if (formatter.hasMoreLines())
|
|
out << streamIterator.getOutputEOL();
|
|
else
|
|
{
|
|
// this can happen if the file if missing a closing brace and break-blocks is requested
|
|
if (formatter.getIsLineReady())
|
|
{
|
|
out << streamIterator.getOutputEOL();
|
|
out << formatter.nextLine();
|
|
}
|
|
}
|
|
}
|
|
|
|
size_t textSizeOut = out.str().length();
|
|
char* pTextOut = fpMemoryAlloc((long)textSizeOut + 1); // call memory allocation function
|
|
if (pTextOut == nullptr)
|
|
{
|
|
fpErrorHandler(120, "Allocation failure on output.");
|
|
return nullptr;
|
|
}
|
|
|
|
strcpy(pTextOut, out.str().c_str());
|
|
#ifndef NDEBUG
|
|
// The checksum is an assert in the console build and ASFormatter.
|
|
// This error returns the incorrectly formatted file to the editor.
|
|
// This is done to allow the file to be saved for debugging purposes.
|
|
if (formatter.getChecksumDiff() != 0)
|
|
fpErrorHandler(220,
|
|
"Checksum error.\n"
|
|
"The incorrectly formatted file will be returned for debugging.");
|
|
#endif
|
|
return pTextOut;
|
|
}
|
|
|
|
extern "C" EXPORT const char* STDCALL AStyleGetVersion(void)
|
|
{
|
|
return g_version;
|
|
}
|
|
|
|
// ASTYLECON_LIB is defined to exclude "main" from the test programs
|
|
#elif !defined(ASTYLECON_LIB)
|
|
|
|
//----------------------------------------------------------------------------
|
|
// main function for ASConsole build
|
|
//----------------------------------------------------------------------------
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
// create objects
|
|
ASFormatter formatter;
|
|
auto console = make_shared<ASConsole>(formatter);
|
|
|
|
// process command line and options file
|
|
// build the vectors fileNameVector, optionsVector, and fileOptionsVector
|
|
vector<string> argvOptions;
|
|
argvOptions = console->getArgvOptions(argc, argv);
|
|
console->processOptions(argvOptions);
|
|
|
|
// if no files have been given, use cin for input and cout for output
|
|
if (!console->fileNameVectorIsEmpty())
|
|
console->processFiles();
|
|
else
|
|
console->formatCinToCout();
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
#endif // ASTYLE_LIB
|