2 // Copyright (c) 2017 by Jim Pattee <jimp03@email.com>.
3 // This code is licensed under the MIT License.
4 // License.md describes the conditions under which this software may be distributed.
6 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7 * AStyle_main source file map.
8 * This source file contains several classes.
9 * They are arranged as follows.
10 * ---------------------------------------
12 * ASStreamIterator methods
21 * } // end of astyle namespace
22 * Global Area ---------------------------
23 * Java Native Interface functions
24 * AStyleMainUtf16 entry point
25 * AStyleMain entry point
26 * AStyleGetVersion entry point
28 * ---------------------------------------
29 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
32 //-----------------------------------------------------------------------------
34 //-----------------------------------------------------------------------------
36 #include "astyle_main.h"
40 #include <clocale> // needed by some compilers
45 // includes for recursive getFileNames() function
47 #undef UNICODE // use ASCII windows functions
58 #include <lib$routines.h>
63 //-----------------------------------------------------------------------------
65 //-----------------------------------------------------------------------------
67 // turn off MinGW automatic file globbing
68 // this CANNOT be in the astyle namespace
73 //----------------------------------------------------------------------------
75 //----------------------------------------------------------------------------
79 // console build variables
82 char g_fileSeparator = '\\'; // Windows file separator
83 bool g_isCaseSensitive = false; // Windows IS NOT case sensitive
85 char g_fileSeparator = '/'; // Linux file separator
86 bool g_isCaseSensitive = true; // Linux IS case sensitive
90 // java library build variables
97 const char* g_version = "3.0";
99 //-----------------------------------------------------------------------------
100 // ASStreamIterator class
101 // typename will be istringstream for GUI and istream otherwise
102 //-----------------------------------------------------------------------------
105 ASStreamIterator<T>::ASStreamIterator(T* in)
113 prevLineDeleted = false;
114 checkForEmptyLine = false;
115 // get length of stream
116 inStream->seekg(0, inStream->end);
117 streamLength = inStream->tellg();
118 inStream->seekg(0, inStream->beg);
122 ASStreamIterator<T>::~ASStreamIterator()
127 * get the length of the input stream.
128 * streamLength variable is set by the constructor.
130 * @return length of the input file stream, converted to an int.
133 int ASStreamIterator<T>::getStreamLength() const
135 return static_cast<int>(streamLength);
139 * read the input stream, delete any end of line characters,
140 * and build a string that contains the input line.
142 * @return string containing the next input line minus any end of line characters
145 string ASStreamIterator<T>::nextLine(bool emptyLineWasDeleted)
147 // verify that the current position is correct
148 assert(peekStart == 0);
150 // a deleted line may be replaced if break-blocks is requested
151 // this sets up the compare to check for a replaced empty line
154 prevLineDeleted = false;
155 checkForEmptyLine = true;
157 if (!emptyLineWasDeleted)
160 prevLineDeleted = true;
162 // read the next record
167 while (!inStream->eof() && ch != '\n' && ch != '\r')
169 buffer.append(1, ch);
178 int peekCh = inStream->peek();
180 // find input end-of-line characters
181 if (!inStream->eof())
183 if (ch == '\r') // CR+LF is windows otherwise Mac OS 9
193 else // LF is Linux, allow for improbable LF/CR
209 // set output end of line characters
210 if (eolWindows >= eolLinux)
212 if (eolWindows >= eolMacOld)
213 outputEOL = "\r\n"; // Windows (CR+LF)
215 outputEOL = "\r"; // MacOld (CR)
217 else if (eolLinux >= eolMacOld)
218 outputEOL = "\n"; // Linux (LF)
220 outputEOL = "\r"; // MacOld (CR)
225 // save the current position and get the next line
226 // this can be called for multiple reads
227 // when finished peeking you MUST call peekReset()
228 // call this function from ASFormatter ONLY
230 string ASStreamIterator<T>::peekNextLine()
232 assert(hasMoreLines());
237 peekStart = inStream->tellg();
239 // read the next record
241 while (!inStream->eof() && ch != '\n' && ch != '\r')
243 nextLine_.append(1, ch);
252 int peekCh = inStream->peek();
254 // remove end-of-line characters
255 if (!inStream->eof())
257 if ((peekCh == '\n' || peekCh == '\r') && peekCh != ch)
264 // reset current position and EOF for peekNextLine()
266 void ASStreamIterator<T>::peekReset()
268 assert(peekStart != 0);
270 inStream->seekg(peekStart);
274 // save the last input line after input has reached EOF
276 void ASStreamIterator<T>::saveLastInputLine()
278 assert(inStream->eof());
282 // return position of the get pointer
284 streamoff ASStreamIterator<T>::tellg()
286 return inStream->tellg();
289 // check for a change in line ends
291 bool ASStreamIterator<T>::getLineEndChange(int lineEndFormat) const
293 assert(lineEndFormat == LINEEND_DEFAULT
294 || lineEndFormat == LINEEND_WINDOWS
295 || lineEndFormat == LINEEND_LINUX
296 || lineEndFormat == LINEEND_MACOLD);
298 bool lineEndChange = false;
299 if (lineEndFormat == LINEEND_WINDOWS)
300 lineEndChange = (eolLinux + eolMacOld != 0);
301 else if (lineEndFormat == LINEEND_LINUX)
302 lineEndChange = (eolWindows + eolMacOld != 0);
303 else if (lineEndFormat == LINEEND_MACOLD)
304 lineEndChange = (eolWindows + eolLinux != 0);
308 lineEndChange = (eolLinux + eolMacOld != 0);
309 else if (eolLinux > 0)
310 lineEndChange = (eolWindows + eolMacOld != 0);
311 else if (eolMacOld > 0)
312 lineEndChange = (eolWindows + eolLinux != 0);
314 return lineEndChange;
317 //-----------------------------------------------------------------------------
319 // main function will be included only in the console build
320 //-----------------------------------------------------------------------------
324 ASConsole::ASConsole(ASFormatter& formatterArg) : formatter(formatterArg)
327 // command line options
331 preserveDate = false;
334 isFormattedOnly = false;
335 ignoreExcludeErrors = false;
336 ignoreExcludeErrorsDisplay = false;
337 optionsFileRequired = false;
340 bypassBrowserOpen = false;
342 filesAreIdentical = true;
343 lineEndsMixed = false;
344 origSuffix = ".orig";
345 mainDirectoryLength = 0;
351 ASConsole::~ASConsole()
354 // rewrite a stringstream converting the line ends
355 void ASConsole::convertLineEnds(ostringstream& out, int lineEnd)
357 assert(lineEnd == LINEEND_WINDOWS || lineEnd == LINEEND_LINUX || lineEnd == LINEEND_MACOLD);
358 const string& inStr = out.str(); // avoids strange looking syntax
359 string outStr; // the converted output
360 int inLength = (int)inStr.length();
361 for (int pos = 0; pos < inLength; pos++)
363 if (inStr[pos] == '\r')
365 if (inStr[pos + 1] == '\n')
368 if (lineEnd == LINEEND_CR)
370 outStr += inStr[pos]; // Delete the LF
374 else if (lineEnd == LINEEND_LF)
376 outStr += inStr[pos + 1]; // Delete the CR
382 outStr += inStr[pos]; // Do not change
383 outStr += inStr[pos + 1];
391 if (lineEnd == LINEEND_CRLF)
393 outStr += inStr[pos]; // Insert the CR
394 outStr += '\n'; // Insert the LF
397 else if (lineEnd == LINEEND_LF)
399 outStr += '\n'; // Insert the LF
404 outStr += inStr[pos]; // Do not change
409 else if (inStr[pos] == '\n')
412 if (lineEnd == LINEEND_CRLF)
414 outStr += '\r'; // Insert the CR
415 outStr += inStr[pos]; // Insert the LF
418 else if (lineEnd == LINEEND_CR)
420 outStr += '\r'; // Insert the CR
425 outStr += inStr[pos]; // Do not change
431 outStr += inStr[pos]; // Write the current char
434 // replace the stream
438 void ASConsole::correctMixedLineEnds(ostringstream& out)
440 LineEndFormat lineEndFormat = LINEEND_DEFAULT;
441 if (outputEOL == "\r\n")
442 lineEndFormat = LINEEND_WINDOWS;
443 if (outputEOL == "\n")
444 lineEndFormat = LINEEND_LINUX;
445 if (outputEOL == "\r")
446 lineEndFormat = LINEEND_MACOLD;
447 convertLineEnds(out, lineEndFormat);
450 // check files for 16 or 32 bit encoding
451 // the file must have a Byte Order Mark (BOM)
452 // NOTE: some string functions don't work with NULLs (e.g. length())
453 FileEncoding ASConsole::detectEncoding(const char* data, size_t dataSize) const
455 FileEncoding encoding = ENCODING_8BIT;
457 if (dataSize >= 4 && memcmp(data, "\x00\x00\xFE\xFF", 4) == 0)
459 else if (dataSize >= 4 && memcmp(data, "\xFF\xFE\x00\x00", 4) == 0)
461 else if (dataSize >= 2 && memcmp(data, "\xFE\xFF", 2) == 0)
463 else if (dataSize >= 2 && memcmp(data, "\xFF\xFE", 2) == 0)
469 // error exit without a message
470 void ASConsole::error() const
472 (*errorStream) << _("\nArtistic Style has terminated") << endl;
476 // error exit with a message
477 void ASConsole::error(const char* why, const char* what) const
479 (*errorStream) << why << ' ' << what << endl;
484 * If no files have been given, use cin for input and cout for output.
486 * This is used to format text for text editors like TextWrangler (Mac).
487 * Do NOT display any console messages when this function is used.
489 void ASConsole::formatCinToCout()
491 // check for files from --stdin= and --stdout=
492 if (!stdPathIn.empty())
494 if (!freopen(stdPathIn.c_str(), "r", stdin))
495 error("Cannot open input file", stdPathIn.c_str());
497 if (!stdPathOut.empty())
499 if (!freopen(stdPathOut.c_str(), "w", stdout))
500 error("Cannot open output file", stdPathOut.c_str());
503 // Using cin.tellg() causes problems with both Windows and Linux.
504 // The Windows problem occurs when the input is not Windows line-ends.
505 // The tellg() will be out of sequence with the get() statements.
506 // The Linux cin.tellg() will return -1 (invalid).
507 // Copying the input sequentially to a stringstream before
508 // formatting solves the problem for both.
509 istream* inStream = &cin;
510 stringstream outStream;
513 while (!inStream->eof() && !inStream->fail())
518 ASStreamIterator<stringstream> streamIterator(&outStream);
519 // Windows pipe or redirection always outputs Windows line-ends.
520 // Linux pipe or redirection will output any line end.
522 LineEndFormat lineEndFormat = LINEEND_DEFAULT;
524 LineEndFormat lineEndFormat = formatter.getLineEndFormat();
526 initializeOutputEOL(lineEndFormat);
527 formatter.init(&streamIterator);
529 while (formatter.hasMoreLines())
531 cout << formatter.nextLine();
532 if (formatter.hasMoreLines())
534 setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
539 // this can happen if the file if missing a closing brace and break-blocks is requested
540 if (formatter.getIsLineReady())
542 setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
544 cout << formatter.nextLine();
552 * Open input file, format it, and close the output.
554 * @param fileName_ The path and name of the file to be processed.
556 void ASConsole::formatFile(const string& fileName_)
560 FileEncoding encoding = readFile(fileName_, in);
562 // Unless a specific language mode has been set, set the language mode
563 // according to the file's suffix.
564 if (!formatter.getModeManuallySet())
566 if (stringEndsWith(fileName_, string(".java")))
567 formatter.setJavaStyle();
568 else if (stringEndsWith(fileName_, string(".cs")))
569 formatter.setSharpStyle();
571 formatter.setCStyle();
574 // set line end format
575 string nextLine; // next output line
576 filesAreIdentical = true; // input and output files are identical
577 LineEndFormat lineEndFormat = formatter.getLineEndFormat();
578 initializeOutputEOL(lineEndFormat);
579 // do this AFTER setting the file mode
580 ASStreamIterator<stringstream> streamIterator(&in);
581 formatter.init(&streamIterator);
584 while (formatter.hasMoreLines())
586 nextLine = formatter.nextLine();
589 if (formatter.hasMoreLines())
591 setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
596 streamIterator.saveLastInputLine(); // to compare the last input line
597 // this can happen if the file if missing a closing brace and break-blocks is requested
598 if (formatter.getIsLineReady())
600 setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
602 nextLine = formatter.nextLine();
605 streamIterator.saveLastInputLine();
609 if (filesAreIdentical)
611 if (streamIterator.checkForEmptyLine)
613 if (nextLine.find_first_not_of(" \t") != string::npos)
614 filesAreIdentical = false;
616 else if (!streamIterator.compareToInputBuffer(nextLine))
617 filesAreIdentical = false;
618 streamIterator.checkForEmptyLine = false;
621 // correct for mixed line ends
624 correctMixedLineEnds(out);
625 filesAreIdentical = false;
628 // remove targetDirectory from filename if required by print
631 displayName = fileName_.substr(targetDirectory.length() + 1);
633 displayName = fileName_;
635 // if file has changed, write the new file
636 if (!filesAreIdentical || streamIterator.getLineEndChange(lineEndFormat))
639 writeFile(fileName_, encoding, out);
640 printMsg(_("Formatted %s\n"), displayName);
645 if (!isFormattedOnly)
646 printMsg(_("Unchanged %s\n"), displayName);
650 assert(formatter.getChecksumDiff() == 0);
653 // build a vector of argv options
654 // the program path argv[0] is excluded
655 vector<string> ASConsole::getArgvOptions(int argc, char** argv) const
657 vector<string> argvOptions;
658 for (int i = 1; i < argc; i++)
660 argvOptions.emplace_back(string(argv[i]));
666 vector<bool> ASConsole::getExcludeHitsVector() const
667 { return excludeHitsVector; }
670 vector<string> ASConsole::getExcludeVector() const
671 { return excludeVector; }
674 vector<string> ASConsole::getFileName() const
678 vector<string> ASConsole::getFileNameVector() const
679 { return fileNameVector; }
682 vector<string> ASConsole::getFileOptionsVector() const
683 { return fileOptionsVector; }
686 bool ASConsole::getFilesAreIdentical() const
687 { return filesAreIdentical; }
690 int ASConsole::getFilesFormatted() const
691 { return filesFormatted; }
694 bool ASConsole::getIgnoreExcludeErrors() const
695 { return ignoreExcludeErrors; }
698 bool ASConsole::getIgnoreExcludeErrorsDisplay() const
699 { return ignoreExcludeErrorsDisplay; }
702 bool ASConsole::getIsDryRun() const
706 bool ASConsole::getIsFormattedOnly() const
707 { return isFormattedOnly; }
710 string ASConsole::getLanguageID() const
711 { return localizer.getLanguageID(); }
714 bool ASConsole::getIsQuiet() const
718 bool ASConsole::getIsRecursive() const
719 { return isRecursive; }
722 bool ASConsole::getIsVerbose() const
723 { return isVerbose; }
726 bool ASConsole::getLineEndsMixed() const
727 { return lineEndsMixed; }
730 bool ASConsole::getNoBackup() const
734 string ASConsole::getOptionsFileName() const
735 { return optionsFileName; }
738 vector<string> ASConsole::getOptionsVector() const
739 { return optionsVector; }
742 string ASConsole::getOrigSuffix() const
743 { return origSuffix; }
746 bool ASConsole::getPreserveDate() const
747 { return preserveDate; }
750 string ASConsole::getStdPathIn() const
751 { return stdPathIn; }
754 string ASConsole::getStdPathOut() const
755 { return stdPathOut; }
758 void ASConsole::setBypassBrowserOpen(bool state)
759 { bypassBrowserOpen = state; }
762 ostream* ASConsole::getErrorStream() const
767 void ASConsole::setErrorStream(ostream* errStreamPtr)
769 errorStream = errStreamPtr;
772 string ASConsole::getParam(const string& arg, const char* op)
774 return arg.substr(strlen(op));
777 // initialize output end of line
778 void ASConsole::initializeOutputEOL(LineEndFormat lineEndFormat)
780 assert(lineEndFormat == LINEEND_DEFAULT
781 || lineEndFormat == LINEEND_WINDOWS
782 || lineEndFormat == LINEEND_LINUX
783 || lineEndFormat == LINEEND_MACOLD);
785 outputEOL.clear(); // current line end
786 prevEOL.clear(); // previous line end
787 lineEndsMixed = false; // output has mixed line ends, LINEEND_DEFAULT only
789 if (lineEndFormat == LINEEND_WINDOWS)
791 else if (lineEndFormat == LINEEND_LINUX)
793 else if (lineEndFormat == LINEEND_MACOLD)
799 FileEncoding ASConsole::readFile(const string& fileName_, stringstream& in) const
801 const int blockSize = 65536; // 64 KB
802 ifstream fin(fileName_.c_str(), ios::binary);
804 error("Cannot open input file", fileName_.c_str());
805 char* data = new (nothrow) char[blockSize];
807 error("Cannot allocate memory for input file", fileName_.c_str());
808 fin.read(data, blockSize);
810 error("Cannot read input file", fileName_.c_str());
811 size_t dataSize = static_cast<size_t>(fin.gcount());
812 FileEncoding encoding = detectEncoding(data, dataSize);
813 if (encoding == UTF_32BE || encoding == UTF_32LE)
814 error(_("Cannot process UTF-32 encoding"), fileName_.c_str());
815 bool firstBlock = true;
816 bool isBigEndian = (encoding == UTF_16BE);
817 while (dataSize != 0)
819 if (encoding == UTF_16LE || encoding == UTF_16BE)
821 // convert utf-16 to utf-8
822 size_t utf8Size = utf8_16.utf8LengthFromUtf16(data, dataSize, isBigEndian);
823 char* utf8Out = new (nothrow) char[utf8Size];
824 if (utf8Out == nullptr)
825 error("Cannot allocate memory for utf-8 conversion", fileName_.c_str());
826 size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize, isBigEndian, firstBlock, utf8Out);
827 assert(utf8Len == utf8Size);
828 in << string(utf8Out, utf8Len);
832 in << string(data, dataSize);
833 fin.read(data, blockSize);
835 error("Cannot read input file", fileName_.c_str());
836 dataSize = static_cast<size_t>(fin.gcount());
844 void ASConsole::setIgnoreExcludeErrors(bool state)
845 { ignoreExcludeErrors = state; }
847 void ASConsole::setIgnoreExcludeErrorsAndDisplay(bool state)
848 { ignoreExcludeErrors = state; ignoreExcludeErrorsDisplay = state; }
850 void ASConsole::setIsFormattedOnly(bool state)
851 { isFormattedOnly = state; }
853 void ASConsole::setIsQuiet(bool state)
856 void ASConsole::setIsRecursive(bool state)
857 { isRecursive = state; }
859 void ASConsole::setIsDryRun(bool state)
860 { isDryRun = state; }
862 void ASConsole::setIsVerbose(bool state)
863 { isVerbose = state; }
865 void ASConsole::setNoBackup(bool state)
866 { noBackup = state; }
868 void ASConsole::setOptionsFileName(const string& name)
869 { optionsFileName = name; }
871 void ASConsole::setOrigSuffix(const string& suffix)
872 { origSuffix = suffix; }
874 void ASConsole::setPreserveDate(bool state)
875 { preserveDate = state; }
877 void ASConsole::setStdPathIn(const string& path)
878 { stdPathIn = path; }
880 void ASConsole::setStdPathOut(const string& path)
881 { stdPathOut = path; }
883 // set outputEOL variable
884 void ASConsole::setOutputEOL(LineEndFormat lineEndFormat, const string& currentEOL)
886 if (lineEndFormat == LINEEND_DEFAULT)
888 outputEOL = currentEOL;
891 if (prevEOL != outputEOL)
893 lineEndsMixed = true;
894 filesAreIdentical = false;
900 prevEOL = currentEOL;
901 if (prevEOL != outputEOL)
902 filesAreIdentical = false;
906 #ifdef _WIN32 // Windows specific
909 * WINDOWS function to display the last system error.
911 void ASConsole::displayLastError()
914 DWORD lastError = GetLastError();
915 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
918 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
923 // Display the string.
924 (*errorStream) << "Error (" << lastError << ") " << msgBuf << endl;
930 * WINDOWS function to get the current directory.
931 * NOTE: getenv("CD") does not work for Windows Vista.
932 * The Windows function GetCurrentDirectory is used instead.
934 * @return The path of the current directory
936 string ASConsole::getCurrentDirectory(const string& fileName_) const
938 char currdir[MAX_PATH];
940 if (!GetCurrentDirectory(sizeof(currdir), currdir))
941 error("Cannot find file", fileName_.c_str());
942 return string(currdir);
946 * WINDOWS function to resolve wildcards and recurse into sub directories.
947 * The fileName vector is filled with the path and names of files to process.
949 * @param directory The path of the directory to be processed.
950 * @param wildcard The wildcard to be processed (e.g. *.cpp).
952 void ASConsole::getFileNames(const string& directory, const string& wildcard)
954 vector<string> subDirectory; // sub directories of directory
955 WIN32_FIND_DATA findFileData; // for FindFirstFile and FindNextFile
957 // Find the first file in the directory
958 // Find will get at least "." and "..".
959 string firstFile = directory + "\\*";
960 HANDLE hFind = FindFirstFile(firstFile.c_str(), &findFileData);
962 if (hFind == INVALID_HANDLE_VALUE)
964 // Error (3) The system cannot find the path specified.
965 // Error (123) The filename, directory name, or volume label syntax is incorrect.
966 // ::FindClose(hFind); before exiting
968 error(_("Cannot open directory"), directory.c_str());
971 // save files and sub directories
974 // skip hidden or read only
975 if (findFileData.cFileName[0] == '.'
976 || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
977 || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
980 // is this a sub directory
981 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
985 // if a sub directory and recursive, save sub directory
986 string subDirectoryPath = directory + g_fileSeparator + findFileData.cFileName;
987 if (isPathExclued(subDirectoryPath))
988 printMsg(_("Exclude %s\n"), subDirectoryPath.substr(mainDirectoryLength));
990 subDirectory.emplace_back(subDirectoryPath);
994 // save the file name
995 string filePathName = directory + g_fileSeparator + findFileData.cFileName;
996 // check exclude before wildcmp to avoid "unmatched exclude" error
997 bool isExcluded = isPathExclued(filePathName);
998 // save file name if wildcard match
999 if (wildcmp(wildcard.c_str(), findFileData.cFileName))
1002 printMsg(_("Exclude %s\n"), filePathName.substr(mainDirectoryLength));
1004 fileName.emplace_back(filePathName);
1007 while (FindNextFile(hFind, &findFileData) != 0);
1009 // check for processing error
1011 DWORD dwError = GetLastError();
1012 if (dwError != ERROR_NO_MORE_FILES)
1013 error("Error processing directory", directory.c_str());
1015 // recurse into sub directories
1016 // if not doing recursive subDirectory is empty
1017 for (unsigned i = 0; i < subDirectory.size(); i++)
1018 getFileNames(subDirectory[i], wildcard);
1024 * WINDOWS function to format a number according to the current locale.
1025 * This formats positive integers only, no float.
1027 * @param num The number to be formatted.
1028 * @param lcid The LCID of the locale to be used for testing.
1029 * @return The formatted number.
1031 string ASConsole::getNumberFormat(int num, size_t lcid) const
1033 #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
1034 // Compilers that don't support C++ locales should still support this assert.
1035 // The C locale should be set but not the C++.
1036 // This function is not necessary if the C++ locale is set.
1037 // The locale().name() return value is not portable to all compilers.
1038 assert(locale().name() == "C");
1040 // convert num to a string
1041 stringstream alphaNum;
1043 string number = alphaNum.str();
1047 // format the number using the Windows API
1049 lcid = LOCALE_USER_DEFAULT;
1050 int outSize = ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, nullptr, 0);
1051 char* outBuf = new (nothrow) char[outSize];
1052 if (outBuf == nullptr)
1054 ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, outBuf, outSize);
1055 string formattedNum(outBuf);
1057 // remove the decimal
1058 int decSize = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, nullptr, 0);
1059 char* decBuf = new (nothrow) char[decSize];
1060 if (decBuf == nullptr)
1062 ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, decBuf, decSize);
1063 size_t i = formattedNum.rfind(decBuf);
1065 if (i != string::npos)
1066 formattedNum.erase(i);
1067 if (!formattedNum.length())
1069 return formattedNum;
1073 * WINDOWS function to open a HTML file in the default browser.
1075 void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
1077 struct stat statbuf;
1078 const char* envPaths[] = { "PROGRAMFILES(X86)", "PROGRAMFILES" };
1079 size_t pathsLen = sizeof(envPaths) / sizeof(envPaths[0]);
1080 string htmlDefaultPath;
1081 for (size_t i = 0; i < pathsLen; i++)
1083 const char* envPath = getenv(envPaths[i]);
1084 if (envPath == nullptr)
1086 htmlDefaultPath = envPath;
1087 if (htmlDefaultPath.length() > 0
1088 && htmlDefaultPath[htmlDefaultPath.length() - 1] == g_fileSeparator)
1089 htmlDefaultPath.erase(htmlDefaultPath.length() - 1);
1090 htmlDefaultPath.append("\\AStyle\\doc");
1091 if (stat(htmlDefaultPath.c_str(), &statbuf) == 0 && statbuf.st_mode & S_IFDIR)
1094 htmlDefaultPath.append("\\");
1097 string htmlFilePath;
1098 if (filePathIn == nullptr)
1099 htmlFilePath = htmlDefaultPath + "astyle.html";
1102 if (strpbrk(filePathIn, "\\/") == nullptr)
1103 htmlFilePath = htmlDefaultPath + filePathIn;
1105 htmlFilePath = filePathIn;
1107 standardizePath(htmlFilePath);
1108 if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
1110 printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
1114 SHELLEXECUTEINFO sei = { sizeof(sei), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1115 sei.fMask = SEE_MASK_FLAG_NO_UI;
1116 sei.lpVerb = "open";
1117 sei.lpFile = htmlFilePath.c_str();
1118 sei.nShow = SW_SHOWNORMAL;
1120 // browser open will be bypassed in test programs
1121 printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
1122 if (!bypassBrowserOpen)
1124 int ret = ShellExecuteEx(&sei);
1126 error(_("Command execute failure"), htmlFilePath.c_str());
1130 #else // Linux specific
1133 * LINUX function to get the current directory.
1134 * This is done if the fileName does not contain a path.
1135 * It is probably from an editor sending a single file.
1137 * @param fileName_ The filename is used only for the error message.
1138 * @return The path of the current directory
1140 string ASConsole::getCurrentDirectory(const string& fileName_) const
1142 char* currdir = getenv("PWD");
1143 if (currdir == nullptr)
1144 error("Cannot find file", fileName_.c_str());
1145 return string(currdir);
1149 * LINUX function to resolve wildcards and recurse into sub directories.
1150 * The fileName vector is filled with the path and names of files to process.
1152 * @param directory The path of the directory to be processed.
1153 * @param wildcard The wildcard to be processed (e.g. *.cpp).
1155 void ASConsole::getFileNames(const string& directory, const string& wildcard)
1157 struct dirent* entry; // entry from readdir()
1158 struct stat statbuf; // entry from stat()
1159 vector<string> subDirectory; // sub directories of this directory
1161 // errno is defined in <errno.h> and is set for errors in opendir, readdir, or stat
1164 DIR* dp = opendir(directory.c_str());
1166 error(_("Cannot open directory"), directory.c_str());
1168 // save the first fileName entry for this recursion
1169 const unsigned firstEntry = fileName.size();
1171 // save files and sub directories
1172 while ((entry = readdir(dp)) != nullptr)
1175 string entryFilepath = directory + g_fileSeparator + entry->d_name;
1176 if (stat(entryFilepath.c_str(), &statbuf) != 0)
1178 if (errno == EOVERFLOW) // file over 2 GB is OK
1183 perror("errno message");
1184 error("Error getting file status in directory", directory.c_str());
1186 // skip hidden or read only
1187 if (entry->d_name[0] == '.' || !(statbuf.st_mode & S_IWUSR))
1189 // if a sub directory and recursive, save sub directory
1190 if (S_ISDIR(statbuf.st_mode) && isRecursive)
1192 if (isPathExclued(entryFilepath))
1193 printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
1195 subDirectory.emplace_back(entryFilepath);
1199 // if a file, save file name
1200 if (S_ISREG(statbuf.st_mode))
1202 // check exclude before wildcmp to avoid "unmatched exclude" error
1203 bool isExcluded = isPathExclued(entryFilepath);
1204 // save file name if wildcard match
1205 if (wildcmp(wildcard.c_str(), entry->d_name) != 0)
1208 printMsg(_("Exclude %s\n"), entryFilepath.substr(mainDirectoryLength));
1210 fileName.emplace_back(entryFilepath);
1215 if (closedir(dp) != 0)
1217 perror("errno message");
1218 error("Error reading directory", directory.c_str());
1221 // sort the current entries for fileName
1222 if (firstEntry < fileName.size())
1223 sort(&fileName[firstEntry], &fileName[fileName.size()]);
1225 // recurse into sub directories
1226 // if not doing recursive, subDirectory is empty
1227 if (subDirectory.size() > 1)
1228 sort(subDirectory.begin(), subDirectory.end());
1229 for (unsigned i = 0; i < subDirectory.size(); i++)
1231 getFileNames(subDirectory[i], wildcard);
1236 * LINUX function to get locale information and call getNumberFormat.
1237 * This formats positive integers only, no float.
1239 * @param num The number to be formatted.
1240 * size_t is for compatibility with the Windows function.
1241 * @return The formatted number.
1243 string ASConsole::getNumberFormat(int num, size_t /*lcid*/) const
1245 #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
1246 // Compilers that don't support C++ locales should still support this assert.
1247 // The C locale should be set but not the C++.
1248 // This function is not necessary if the C++ locale is set.
1249 // The locale().name() return value is not portable to all compilers.
1250 assert(locale().name() == "C");
1253 // get the locale info
1257 // format the number
1258 return getNumberFormat(num, lc->grouping, lc->thousands_sep);
1262 * LINUX function to format a number according to the current locale.
1263 * This formats positive integers only, no float.
1265 * @param num The number to be formatted.
1266 * @param groupingArg The grouping string from the locale.
1267 * @param separator The thousands group separator from the locale.
1268 * @return The formatted number.
1270 string ASConsole::getNumberFormat(int num, const char* groupingArg, const char* separator) const
1272 // convert num to a string
1273 stringstream alphaNum;
1275 string number = alphaNum.str();
1276 // format the number from right to left
1277 string formattedNum;
1278 size_t ig = 0; // grouping index
1279 int grouping = groupingArg[ig];
1280 int i = number.length();
1281 // check for no grouping
1283 grouping = number.length();
1286 // extract a group of numbers
1291 group = number.substr(i - grouping);
1292 // update formatted number
1293 formattedNum.insert(0, group);
1298 formattedNum.insert(0, separator);
1301 if (groupingArg[ig] != '\0'
1302 && groupingArg[ig + 1] != '\0')
1303 grouping = groupingArg[++ig];
1305 return formattedNum;
1309 * LINUX function to open a HTML file in the default browser.
1310 * Use xdg-open from freedesktop.org cross-desktop compatibility suite xdg-utils.
1311 * see http://portland.freedesktop.org/wiki/
1312 * This is installed on most modern distributions.
1314 void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
1316 struct stat statbuf;
1317 string htmlDefaultPath = "/usr/share/doc/astyle/html/";
1318 string htmlDefaultFile = "astyle.html";
1321 string htmlFilePath;
1322 if (filePathIn == nullptr)
1323 htmlFilePath = htmlDefaultPath + htmlDefaultFile;
1326 if (strpbrk(filePathIn, "\\/") == nullptr)
1327 htmlFilePath = htmlDefaultPath + filePathIn;
1329 htmlFilePath = filePathIn;
1331 standardizePath(htmlFilePath);
1332 if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
1334 printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
1339 const char* envPaths = getenv("PATH");
1340 if (envPaths == nullptr)
1342 size_t envlen = strlen(envPaths);
1343 char* paths = new char[envlen + 1];
1344 strcpy(paths, envPaths);
1345 // find xdg-open (usually in /usr/bin)
1346 // Mac uses open instead
1348 const char* fileOpen = "open";
1350 const char* fileOpen = "xdg-open";
1353 char* searchDir = strtok(paths, ":");
1354 while (searchDir != nullptr)
1356 searchPath = searchDir;
1357 if (searchPath.length() > 0
1358 && searchPath[searchPath.length() - 1] != g_fileSeparator)
1359 searchPath.append(string(1, g_fileSeparator));
1360 searchPath.append(fileOpen);
1361 if (stat(searchPath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
1363 searchDir = strtok(nullptr, ":");
1366 if (searchDir == nullptr)
1367 error(_("Command is not installed"), fileOpen);
1369 // browser open will be bypassed in test programs
1370 printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
1371 if (!bypassBrowserOpen)
1373 execlp(fileOpen, fileOpen, htmlFilePath.c_str(), nullptr);
1374 // execlp will NOT return if successful
1375 error(_("Command execute failure"), fileOpen);
1381 // get individual file names from the command-line file path
1382 void ASConsole::getFilePaths(const string& filePath)
1385 targetDirectory = string();
1386 targetFilename = string();
1388 // separate directory and file name
1389 size_t separator = filePath.find_last_of(g_fileSeparator);
1390 if (separator == string::npos)
1392 // if no directory is present, use the currently active directory
1393 targetDirectory = getCurrentDirectory(filePath);
1394 targetFilename = filePath;
1395 mainDirectoryLength = targetDirectory.length() + 1; // +1 includes trailing separator
1399 targetDirectory = filePath.substr(0, separator);
1400 targetFilename = filePath.substr(separator + 1);
1401 mainDirectoryLength = targetDirectory.length() + 1; // +1 includes trailing separator
1404 if (targetFilename.length() == 0)
1406 fprintf(stderr, _("Missing filename in %s\n"), filePath.c_str());
1410 // check filename for wildcards
1411 hasWildcard = false;
1412 if (targetFilename.find_first_of("*?") != string::npos)
1415 // clear exclude hits vector
1416 size_t excludeHitsVectorSize = excludeHitsVector.size();
1417 for (size_t ix = 0; ix < excludeHitsVectorSize; ix++)
1418 excludeHitsVector[ix] = false;
1420 // If the filename is not quoted on Linux, bash will replace the
1421 // wildcard instead of passing it to the program.
1422 if (isRecursive && !hasWildcard)
1424 fprintf(stderr, "%s\n", _("Recursive option with no wildcard"));
1426 fprintf(stderr, "%s\n", _("Did you intend quote the filename"));
1431 // display directory name for wildcard processing
1434 printSeparatingLine();
1435 printMsg(_("Directory %s\n"), targetDirectory + g_fileSeparator + targetFilename);
1438 // create a vector of paths and file names to process
1439 if (hasWildcard || isRecursive)
1440 getFileNames(targetDirectory, targetFilename);
1443 // verify a single file is not a directory (needed on Linux)
1444 string entryFilepath = targetDirectory + g_fileSeparator + targetFilename;
1445 struct stat statbuf;
1446 if (stat(entryFilepath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
1447 fileName.emplace_back(entryFilepath);
1450 // check for unprocessed excludes
1451 bool excludeErr = false;
1452 for (size_t ix = 0; ix < excludeHitsVector.size(); ix++)
1454 if (!excludeHitsVector[ix])
1457 if (!ignoreExcludeErrorsDisplay)
1459 if (ignoreExcludeErrors)
1460 printMsg(_("Exclude (unmatched) %s\n"), excludeVector[ix]);
1462 fprintf(stderr, _("Exclude (unmatched) %s\n"), excludeVector[ix].c_str());
1466 if (!ignoreExcludeErrors)
1467 fprintf(stderr, _("Exclude (unmatched) %s\n"), excludeVector[ix].c_str());
1472 if (excludeErr && !ignoreExcludeErrors)
1474 if (hasWildcard && !isRecursive)
1475 fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
1479 // check if files were found (probably an input error if not)
1480 if (fileName.empty())
1482 fprintf(stderr, _("No file to process %s\n"), filePath.c_str());
1483 if (hasWildcard && !isRecursive)
1484 fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
1489 printSeparatingLine();
1492 bool ASConsole::fileNameVectorIsEmpty() const
1494 return fileNameVector.empty();
1497 bool ASConsole::isOption(const string& arg, const char* op)
1499 return arg.compare(op) == 0;
1502 bool ASConsole::isOption(const string& arg, const char* a, const char* b)
1504 return (isOption(arg, a) || isOption(arg, b));
1507 bool ASConsole::isParamOption(const string& arg, const char* option)
1509 bool retVal = arg.compare(0, strlen(option), option) == 0;
1510 // if comparing for short option, 2nd char of arg must be numeric
1511 if (retVal && strlen(option) == 1 && arg.length() > 1)
1512 if (!isdigit((unsigned char)arg[1]))
1517 // compare a path to the exclude vector
1518 // used for both directories and filenames
1519 // updates the g_excludeHitsVector
1520 // return true if a match
1521 bool ASConsole::isPathExclued(const string& subPath)
1523 bool retVal = false;
1525 // read the exclude vector checking for a match
1526 for (size_t i = 0; i < excludeVector.size(); i++)
1528 string exclude = excludeVector[i];
1530 if (subPath.length() < exclude.length())
1533 size_t compareStart = subPath.length() - exclude.length();
1534 // subPath compare must start with a directory name
1535 if (compareStart > 0)
1537 char lastPathChar = subPath[compareStart - 1];
1538 if (lastPathChar != g_fileSeparator)
1542 string compare = subPath.substr(compareStart);
1543 if (!g_isCaseSensitive)
1545 // make it case insensitive for Windows
1546 for (size_t j = 0; j < compare.length(); j++)
1547 compare[j] = (char)tolower(compare[j]);
1548 for (size_t j = 0; j < exclude.length(); j++)
1549 exclude[j] = (char)tolower(exclude[j]);
1551 // compare sub directory to exclude data - must check them all
1552 if (compare == exclude)
1554 excludeHitsVector[i] = true;
1562 void ASConsole::printHelp() const
1565 cout << " Artistic Style " << g_version << endl;
1566 cout << " Maintained by: Jim Pattee\n";
1567 cout << " Original Author: Tal Davidson\n";
1571 cout << " astyle [OPTIONS] File1 File2 File3 [...]\n";
1573 cout << " astyle [OPTIONS] < Original > Beautified\n";
1575 cout << " When indenting a specific file, the resulting indented file RETAINS\n";
1576 cout << " the original file-name. The original pre-indented file is renamed,\n";
1577 cout << " with a suffix of \'.orig\' added to the original filename.\n";
1579 cout << " Wildcards (* and ?) may be used in the filename.\n";
1580 cout << " A \'recursive\' option can process directories recursively.\n";
1582 cout << " By default, astyle is set up to indent with four spaces per indent,\n";
1583 cout << " a maximal indentation of 40 spaces inside continuous statements,\n";
1584 cout << " a minimum indentation of eight spaces inside conditional statements,\n";
1585 cout << " and NO formatting options.\n";
1587 cout << "Options:\n";
1588 cout << "--------\n";
1589 cout << " This program follows the usual GNU command line syntax.\n";
1590 cout << " Long options (starting with '--') must be written one at a time.\n";
1591 cout << " Short options (starting with '-') may be appended together.\n";
1592 cout << " Thus, -bps4 is the same as -b -p -s4.\n";
1594 cout << "Options File:\n";
1595 cout << "-------------\n";
1596 cout << " Artistic Style looks for a default options file in the\n";
1597 cout << " following order:\n";
1598 cout << " 1. The contents of the ARTISTIC_STYLE_OPTIONS environment\n";
1599 cout << " variable if it exists.\n";
1600 cout << " 2. The file called .astylerc in the directory pointed to by the\n";
1601 cout << " HOME environment variable ( i.e. $HOME/.astylerc ).\n";
1602 cout << " 3. The file called astylerc in the directory pointed to by the\n";
1603 cout << " USERPROFILE environment variable (i.e. %USERPROFILE%\\astylerc).\n";
1604 cout << " If a default options file is found, the options in this file will\n";
1605 cout << " be parsed BEFORE the command-line options.\n";
1606 cout << " Long options within the default option file may be written without\n";
1607 cout << " the preliminary '--'.\n";
1609 cout << "Disable Formatting:\n";
1610 cout << "-------------------\n";
1611 cout << " Disable Block\n";
1612 cout << " Blocks of code can be disabled with the comment tags *INDENT-OFF*\n";
1613 cout << " and *INDENT-ON*. It must be contained in a one-line comment.\n";
1615 cout << " Disable Line\n";
1616 cout << " Padding of operators can be disabled on a single line using the\n";
1617 cout << " comment tag *NOPAD*. It must be contained in a line-end comment.\n";
1619 cout << "Brace Style Options:\n";
1620 cout << "--------------------\n";
1621 cout << " default brace style\n";
1622 cout << " If no brace style is requested, the opening braces will not be\n";
1623 cout << " changed and closing braces will be broken from the preceding line.\n";
1625 cout << " --style=allman OR --style=bsd OR --style=break OR -A1\n";
1626 cout << " Allman style formatting/indenting.\n";
1627 cout << " Broken braces.\n";
1629 cout << " --style=java OR --style=attach OR -A2\n";
1630 cout << " Java style formatting/indenting.\n";
1631 cout << " Attached braces.\n";
1633 cout << " --style=kr OR --style=k&r OR --style=k/r OR -A3\n";
1634 cout << " Kernighan & Ritchie style formatting/indenting.\n";
1635 cout << " Linux braces.\n";
1637 cout << " --style=stroustrup OR -A4\n";
1638 cout << " Stroustrup style formatting/indenting.\n";
1639 cout << " Linux braces.\n";
1641 cout << " --style=whitesmith OR -A5\n";
1642 cout << " Whitesmith style formatting/indenting.\n";
1643 cout << " Broken, indented braces.\n";
1644 cout << " Indented class blocks and switch blocks.\n";
1646 cout << " --style=vtk OR -A15\n";
1647 cout << " VTK style formatting/indenting.\n";
1648 cout << " Broken, indented braces except for the opening braces.\n";
1650 cout << " --style=banner OR -A6\n";
1651 cout << " Banner style formatting/indenting.\n";
1652 cout << " Attached, indented braces.\n";
1654 cout << " --style=gnu OR -A7\n";
1655 cout << " GNU style formatting/indenting.\n";
1656 cout << " Broken braces, indented blocks.\n";
1658 cout << " --style=linux OR --style=knf OR -A8\n";
1659 cout << " Linux style formatting/indenting.\n";
1660 cout << " Linux braces, minimum conditional indent is one-half indent.\n";
1662 cout << " --style=horstmann OR --style=run-in OR -A9\n";
1663 cout << " Horstmann style formatting/indenting.\n";
1664 cout << " Run-in braces, indented switches.\n";
1666 cout << " --style=1tbs OR --style=otbs OR -A10\n";
1667 cout << " One True Brace Style formatting/indenting.\n";
1668 cout << " Linux braces, add braces to all conditionals.\n";
1670 cout << " --style=google OR -A14\n";
1671 cout << " Google style formatting/indenting.\n";
1672 cout << " Attached braces, indented class modifiers.\n";
1674 cout << " --style=mozilla OR -A16\n";
1675 cout << " Mozilla style formatting/indenting.\n";
1676 cout << " Linux braces, with broken braces for structs and enums,\n";
1677 cout << " and attached braces for namespaces.\n";
1679 cout << " --style=pico OR -A11\n";
1680 cout << " Pico style formatting/indenting.\n";
1681 cout << " Run-in opening braces and attached closing braces.\n";
1682 cout << " Uses keep one line blocks and keep one line statements.\n";
1684 cout << " --style=lisp OR -A12\n";
1685 cout << " Lisp style formatting/indenting.\n";
1686 cout << " Attached opening braces and attached closing braces.\n";
1687 cout << " Uses keep one line statements.\n";
1689 cout << "Tab Options:\n";
1690 cout << "------------\n";
1691 cout << " default indent option\n";
1692 cout << " If no indentation option is set, the default\n";
1693 cout << " option of 4 spaces per indent will be used.\n";
1695 cout << " --indent=spaces=# OR -s#\n";
1696 cout << " Indent using # spaces per indent. Not specifying #\n";
1697 cout << " will result in a default of 4 spaces per indent.\n";
1699 cout << " --indent=tab OR --indent=tab=# OR -t OR -t#\n";
1700 cout << " Indent using tab characters, assuming that each\n";
1701 cout << " indent is # spaces long. Not specifying # will result\n";
1702 cout << " in a default assumption of 4 spaces per indent.\n";
1704 cout << " --indent=force-tab=# OR -T#\n";
1705 cout << " Indent using tab characters, assuming that each\n";
1706 cout << " indent is # spaces long. Force tabs to be used in areas\n";
1707 cout << " AStyle would prefer to use spaces.\n";
1709 cout << " --indent=force-tab-x=# OR -xT#\n";
1710 cout << " Allows the tab length to be set to a length that is different\n";
1711 cout << " from the indent length. This may cause the indentation to be\n";
1712 cout << " a mix of both spaces and tabs. This option sets the tab length.\n";
1714 cout << "Brace Modify Options:\n";
1715 cout << "---------------------\n";
1716 cout << " --attach-namespaces OR -xn\n";
1717 cout << " Attach braces to a namespace statement.\n";
1719 cout << " --attach-classes OR -xc\n";
1720 cout << " Attach braces to a class statement.\n";
1722 cout << " --attach-inlines OR -xl\n";
1723 cout << " Attach braces to class inline function definitions.\n";
1725 cout << " --attach-extern-c OR -xk\n";
1726 cout << " Attach braces to an extern \"C\" statement.\n";
1728 cout << " --attach-closing-while OR -xV\n";
1729 cout << " Attach closing while of do-while to the closing brace.\n";
1731 cout << "Indentation Options:\n";
1732 cout << "--------------------\n";
1733 cout << " --indent-classes OR -C\n";
1734 cout << " Indent 'class' blocks so that the entire block is indented.\n";
1736 cout << " --indent-modifiers OR -xG\n";
1737 cout << " Indent 'class' access modifiers, 'public:', 'protected:' or\n";
1738 cout << " 'private:', one half indent. The rest of the class is not\n";
1739 cout << " indented. \n";
1741 cout << " --indent-switches OR -S\n";
1742 cout << " Indent 'switch' blocks, so that the inner 'case XXX:'\n";
1743 cout << " headers are indented in relation to the switch block.\n";
1745 cout << " --indent-cases OR -K\n";
1746 cout << " Indent case blocks from the 'case XXX:' headers.\n";
1747 cout << " Case statements not enclosed in blocks are NOT indented.\n";
1749 cout << " --indent-namespaces OR -N\n";
1750 cout << " Indent the contents of namespace blocks.\n";
1752 cout << " --indent-after-parens OR -xU\n";
1753 cout << " Indent, instead of align, continuation lines following lines\n";
1754 cout << " that contain an opening paren '(' or an assignment '='. \n";
1756 cout << " --indent-continuation=# OR -xt#\n";
1757 cout << " Indent continuation lines an additional # indents.\n";
1758 cout << " The valid values are 0 thru 4 indents.\n";
1759 cout << " The default value is 1 indent.\n";
1761 cout << " --indent-labels OR -L\n";
1762 cout << " Indent labels so that they appear one indent less than\n";
1763 cout << " the current indentation level, rather than being\n";
1764 cout << " flushed completely to the left (which is the default).\n";
1766 cout << " --indent-preproc-block OR -xW\n";
1767 cout << " Indent preprocessor blocks at brace level 0.\n";
1768 cout << " Without this option the preprocessor block is not indented.\n";
1770 cout << " --indent-preproc-cond OR -xw\n";
1771 cout << " Indent preprocessor conditional statements #if/#else/#endif\n";
1772 cout << " to the same level as the source code.\n";
1774 cout << " --indent-preproc-define OR -w\n";
1775 cout << " Indent multi-line preprocessor #define statements.\n";
1777 cout << " --indent-col1-comments OR -Y\n";
1778 cout << " Indent line comments that start in column one.\n";
1780 cout << " --min-conditional-indent=# OR -m#\n";
1781 cout << " Indent a minimal # spaces in a continuous conditional\n";
1782 cout << " belonging to a conditional header.\n";
1783 cout << " The valid values are:\n";
1784 cout << " 0 - no minimal indent.\n";
1785 cout << " 1 - indent at least one additional indent.\n";
1786 cout << " 2 - indent at least two additional indents.\n";
1787 cout << " 3 - indent at least one-half an additional indent.\n";
1788 cout << " The default value is 2, two additional indents.\n";
1790 cout << " --max-continuation-indent=# OR -M#\n";
1791 cout << " Indent a maximal # spaces in a continuation line,\n";
1792 cout << " relative to the previous line.\n";
1793 cout << " The valid values are 40 thru 120.\n";
1794 cout << " The default value is 40.\n";
1796 cout << "Padding Options:\n";
1797 cout << "----------------\n";
1798 cout << " --break-blocks OR -f\n";
1799 cout << " Insert empty lines around unrelated blocks, labels, classes, ...\n";
1801 cout << " --break-blocks=all OR -F\n";
1802 cout << " Like --break-blocks, except also insert empty lines \n";
1803 cout << " around closing headers (e.g. 'else', 'catch', ...).\n";
1805 cout << " --pad-oper OR -p\n";
1806 cout << " Insert space padding around operators.\n";
1808 cout << " --pad-comma OR -xg\n";
1809 cout << " Insert space padding after commas.\n";
1811 cout << " --pad-paren OR -P\n";
1812 cout << " Insert space padding around parenthesis on both the outside\n";
1813 cout << " and the inside.\n";
1815 cout << " --pad-paren-out OR -d\n";
1816 cout << " Insert space padding around parenthesis on the outside only.\n";
1818 cout << " --pad-first-paren-out OR -xd\n";
1819 cout << " Insert space padding around first parenthesis in a series on\n";
1820 cout << " the outside only.\n";
1822 cout << " --pad-paren-in OR -D\n";
1823 cout << " Insert space padding around parenthesis on the inside only.\n";
1825 cout << " --pad-header OR -H\n";
1826 cout << " Insert space padding after paren headers (e.g. 'if', 'for'...).\n";
1828 cout << " --unpad-paren OR -U\n";
1829 cout << " Remove unnecessary space padding around parenthesis. This\n";
1830 cout << " can be used in combination with the 'pad' options above.\n";
1832 cout << " --delete-empty-lines OR -xd\n";
1833 cout << " Delete empty lines within a function or method.\n";
1834 cout << " It will NOT delete lines added by the break-blocks options.\n";
1836 cout << " --fill-empty-lines OR -E\n";
1837 cout << " Fill empty lines with the white space of their\n";
1838 cout << " previous lines.\n";
1840 cout << " --align-pointer=type OR -k1\n";
1841 cout << " --align-pointer=middle OR -k2\n";
1842 cout << " --align-pointer=name OR -k3\n";
1843 cout << " Attach a pointer or reference operator (*, &, or ^) to either\n";
1844 cout << " the operator type (left), middle, or operator name (right).\n";
1845 cout << " To align the reference separately use --align-reference.\n";
1847 cout << " --align-reference=none OR -W0\n";
1848 cout << " --align-reference=type OR -W1\n";
1849 cout << " --align-reference=middle OR -W2\n";
1850 cout << " --align-reference=name OR -W3\n";
1851 cout << " Attach a reference operator (&) to either\n";
1852 cout << " the operator type (left), middle, or operator name (right).\n";
1853 cout << " If not set, follow pointer alignment.\n";
1855 cout << "Formatting Options:\n";
1856 cout << "-------------------\n";
1857 cout << " --break-closing-braces OR -y\n";
1858 cout << " Break braces before closing headers (e.g. 'else', 'catch', ...).\n";
1859 cout << " Use with --style=java, --style=kr, --style=stroustrup,\n";
1860 cout << " --style=linux, or --style=1tbs.\n";
1862 cout << " --break-elseifs OR -e\n";
1863 cout << " Break 'else if()' statements into two different lines.\n";
1865 cout << " --break-one-line-headers OR -xb\n";
1866 cout << " Break one line headers (e.g. 'if', 'while', 'else', ...) from a\n";
1867 cout << " statement residing on the same line.\n";
1869 cout << " --add-braces OR -j\n";
1870 cout << " Add braces to unbraced one line conditional statements.\n";
1872 cout << " --add-one-line-braces OR -J\n";
1873 cout << " Add one line braces to unbraced one line conditional\n";
1874 cout << " statements.\n";
1876 cout << " --remove-braces OR -xj\n";
1877 cout << " Remove braces from a braced one line conditional statements.\n";
1879 cout << " --keep-one-line-blocks OR -O\n";
1880 cout << " Don't break blocks residing completely on one line.\n";
1882 cout << " --keep-one-line-statements OR -o\n";
1883 cout << " Don't break lines containing multiple statements into\n";
1884 cout << " multiple single-statement lines.\n";
1886 cout << " --convert-tabs OR -c\n";
1887 cout << " Convert tabs to the appropriate number of spaces.\n";
1889 cout << " --close-templates OR -xy\n";
1890 cout << " Close ending angle brackets on template definitions.\n";
1892 cout << " --remove-comment-prefix OR -xp\n";
1893 cout << " Remove the leading '*' prefix on multi-line comments and\n";
1894 cout << " indent the comment text one indent.\n";
1896 cout << " --max-code-length=# OR -xC#\n";
1897 cout << " --break-after-logical OR -xL\n";
1898 cout << " max-code-length=# will break the line if it exceeds more than\n";
1899 cout << " # characters. The valid values are 50 thru 200.\n";
1900 cout << " If the line contains logical conditionals they will be placed\n";
1901 cout << " first on the new line. The option break-after-logical will\n";
1902 cout << " cause the logical conditional to be placed last on the\n";
1903 cout << " previous line.\n";
1905 cout << " --mode=c\n";
1906 cout << " Indent a C or C++ source file (this is the default).\n";
1908 cout << " --mode=java\n";
1909 cout << " Indent a Java source file.\n";
1911 cout << " --mode=cs\n";
1912 cout << " Indent a C# source file.\n";
1914 cout << "Objective-C Options:\n";
1915 cout << "--------------------\n";
1916 cout << " --pad-method-prefix OR -xQ\n";
1917 cout << " Insert space padding after the '-' or '+' Objective-C\n";
1918 cout << " method prefix.\n";
1920 cout << " --unpad-method-prefix OR -xR\n";
1921 cout << " Remove all space padding after the '-' or '+' Objective-C\n";
1922 cout << " method prefix.\n";
1924 cout << " --pad-return-type OR -xq\n";
1925 cout << " Insert space padding after the Objective-C return type.\n";
1927 cout << " --unpad-return-type OR -xr\n";
1928 cout << " Remove all space padding after the Objective-C return type.\n";
1930 cout << " --pad-param-type OR -xS\n";
1931 cout << " Insert space padding after the Objective-C return type.\n";
1933 cout << " --unpad-param-type OR -xs\n";
1934 cout << " Remove all space padding after the Objective-C return type.\n";
1936 cout << " --align-method-colon OR -xM\n";
1937 cout << " Align the colons in an Objective-C method definition.\n";
1939 cout << " --pad-method-colon=none OR -xP\n";
1940 cout << " --pad-method-colon=all OR -xP1\n";
1941 cout << " --pad-method-colon=after OR -xP2\n";
1942 cout << " --pad-method-colon=before OR -xP3\n";
1943 cout << " Add or remove space padding before or after the colons in an\n";
1944 cout << " Objective-C method call.\n";
1946 cout << "Other Options:\n";
1947 cout << "--------------\n";
1948 cout << " --suffix=####\n";
1949 cout << " Append the suffix #### instead of '.orig' to original filename.\n";
1951 cout << " --suffix=none OR -n\n";
1952 cout << " Do not retain a backup of the original file.\n";
1954 cout << " --recursive OR -r OR -R\n";
1955 cout << " Process subdirectories recursively.\n";
1957 cout << " --dry-run\n";
1958 cout << " Perform a trial run with no changes made to check for formatting.\n";
1960 cout << " --exclude=####\n";
1961 cout << " Specify a file or directory #### to be excluded from processing.\n";
1963 cout << " --ignore-exclude-errors OR -i\n";
1964 cout << " Allow processing to continue if there are errors in the exclude=####\n";
1965 cout << " options. It will display the unmatched excludes.\n";
1967 cout << " --ignore-exclude-errors-x OR -xi\n";
1968 cout << " Allow processing to continue if there are errors in the exclude=####\n";
1969 cout << " options. It will NOT display the unmatched excludes.\n";
1971 cout << " --errors-to-stdout OR -X\n";
1972 cout << " Print errors and help information to standard-output rather than\n";
1973 cout << " to standard-error.\n";
1975 cout << " --preserve-date OR -Z\n";
1976 cout << " Preserve the original file's date and time modified. The time\n";
1977 cout << " modified will be changed a few micro seconds to force a compile.\n";
1979 cout << " --verbose OR -v\n";
1980 cout << " Verbose mode. Extra informational messages will be displayed.\n";
1982 cout << " --formatted OR -Q\n";
1983 cout << " Formatted display mode. Display only the files that have been\n";
1984 cout << " formatted.\n";
1986 cout << " --quiet OR -q\n";
1987 cout << " Quiet mode. Suppress all output except error messages.\n";
1989 cout << " --lineend=windows OR -z1\n";
1990 cout << " --lineend=linux OR -z2\n";
1991 cout << " --lineend=macold OR -z3\n";
1992 cout << " Force use of the specified line end style. Valid options\n";
1993 cout << " are windows (CRLF), linux (LF), and macold (CR).\n";
1995 cout << "Command Line Only:\n";
1996 cout << "------------------\n";
1997 cout << " --options=####\n";
1998 cout << " Specify an options file #### to read and use.\n";
2000 cout << " --options=none\n";
2001 cout << " Disable the default options file.\n";
2002 cout << " Only the command-line parameters will be used.\n";
2004 cout << " --ascii OR -I\n";
2005 cout << " The displayed output will be ascii characters only.\n";
2007 cout << " --version OR -V\n";
2008 cout << " Print version number.\n";
2010 cout << " --help OR -h OR -?\n";
2011 cout << " Print this help message.\n";
2013 cout << " --html OR -!\n";
2014 cout << " Open the HTML help file \"astyle.html\" in the default browser.\n";
2015 cout << " The documentation must be installed in the standard install path.\n";
2017 cout << " --html=####\n";
2018 cout << " Open a HTML help file in the default browser using the file path\n";
2019 cout << " ####. The path may include a directory path and a file name, or a\n";
2020 cout << " file name only. Paths containing spaces must be enclosed in quotes.\n";
2026 * Process files in the fileNameVector.
2028 void ASConsole::processFiles()
2031 printVerboseHeader();
2033 clock_t startTime = clock(); // start time of file formatting
2035 // loop thru input fileNameVector and process the files
2036 for (size_t i = 0; i < fileNameVector.size(); i++)
2038 getFilePaths(fileNameVector[i]);
2040 // loop thru fileName vector formatting the files
2041 for (size_t j = 0; j < fileName.size(); j++)
2042 formatFile(fileName[j]);
2045 // files are processed, display stats
2047 printVerboseStats(startTime);
2050 // process options from the command line and options file
2051 // build the vectors fileNameVector, excludeVector, optionsVector, and fileOptionsVector
2052 void ASConsole::processOptions(const vector<string>& argvOptions)
2056 bool shouldParseOptionsFile = true;
2058 // get command line options
2059 for (size_t i = 0; i < argvOptions.size(); i++)
2061 arg = argvOptions[i];
2063 if ( isOption(arg, "-I" )
2064 || isOption(arg, "--ascii") )
2067 setlocale(LC_ALL, "C"); // use English decimal indicator
2068 localizer.setLanguageFromName("en");
2070 else if ( isOption(arg, "--options=none") )
2072 shouldParseOptionsFile = false;
2074 else if ( isParamOption(arg, "--options=") )
2076 optionsFileName = getParam(arg, "--options=");
2077 optionsFileRequired = true;
2078 if (optionsFileName.empty())
2079 setOptionsFileName(" ");
2081 else if ( isOption(arg, "-h")
2082 || isOption(arg, "--help")
2083 || isOption(arg, "-?") )
2088 else if ( isOption(arg, "-!")
2089 || isOption(arg, "--html") )
2091 launchDefaultBrowser();
2094 else if ( isParamOption(arg, "--html=") )
2096 string htmlFilePath = getParam(arg, "--html=");
2097 launchDefaultBrowser(htmlFilePath.c_str());
2100 else if ( isOption(arg, "-V" )
2101 || isOption(arg, "--version") )
2103 printf("Artistic Style Version %s\n", g_version);
2106 else if (arg[0] == '-')
2108 optionsVector.emplace_back(arg);
2112 standardizePath(arg);
2113 fileNameVector.emplace_back(arg);
2117 // get options file path and name
2118 if (shouldParseOptionsFile)
2120 if (optionsFileName.empty())
2122 char* env = getenv("ARTISTIC_STYLE_OPTIONS");
2124 setOptionsFileName(env);
2126 if (optionsFileName.empty())
2128 char* env = getenv("HOME");
2130 setOptionsFileName(string(env) + "/.astylerc");
2132 if (optionsFileName.empty())
2134 char* env = getenv("USERPROFILE");
2136 setOptionsFileName(string(env) + "/astylerc");
2138 if (!optionsFileName.empty())
2139 standardizePath(optionsFileName);
2142 // create the options file vector and parse the options for errors
2143 ASOptions options(formatter, *this);
2144 if (!optionsFileName.empty())
2146 ifstream optionsIn(optionsFileName.c_str());
2149 options.importOptions(optionsIn, fileOptionsVector);
2150 ok = options.parseOptions(fileOptionsVector,
2151 string(_("Invalid option file options:")));
2155 if (optionsFileRequired)
2156 error(_("Cannot open options file"), optionsFileName.c_str());
2157 optionsFileName.clear();
2163 (*errorStream) << options.getOptionErrors() << endl;
2164 (*errorStream) << _("For help on options type 'astyle -h'") << endl;
2168 // parse the command line options vector for errors
2169 ok = options.parseOptions(optionsVector,
2170 string(_("Invalid command line options:")));
2173 (*errorStream) << options.getOptionErrors() << endl;
2174 (*errorStream) << _("For help on options type 'astyle -h'") << endl;
2179 // remove a file and check for an error
2180 void ASConsole::removeFile(const char* fileName_, const char* errMsg) const
2182 if (remove(fileName_) != 0)
2184 if (errno == ENOENT) // no file is OK
2188 perror("errno message");
2189 error(errMsg, fileName_);
2194 // rename a file and check for an error
2195 void ASConsole::renameFile(const char* oldFileName, const char* newFileName, const char* errMsg) const
2197 int result = rename(oldFileName, newFileName);
2200 // if file still exists the remove needs more time - retry
2201 if (errno == EEXIST)
2204 waitForRemove(newFileName);
2205 result = rename(oldFileName, newFileName);
2209 perror("errno message");
2210 error(errMsg, oldFileName);
2215 // make sure file separators are correct type (Windows or Linux)
2216 // remove ending file separator
2217 // remove beginning file separator if requested and NOT a complete file path
2218 void ASConsole::standardizePath(string& path, bool removeBeginningSeparator /*false*/) const
2223 char less[NAML$C_MAXRSS];
2224 char sess[NAM$C_MAXRSS];
2227 // If we are on a VMS system, translate VMS style filenames to unix
2230 fab.fab$l_fna = (char*) -1; // *NOPAD*
2232 fab.fab$l_naml = &naml;
2234 strcpy(sess, path.c_str());
2235 naml.naml$l_long_filename = (char*)sess;
2236 naml.naml$l_long_filename_size = path.length();
2237 naml.naml$l_long_expand = less;
2238 naml.naml$l_long_expand_alloc = sizeof(less);
2239 naml.naml$l_esa = sess;
2240 naml.naml$b_ess = sizeof(sess);
2241 naml.naml$v_no_short_upcase = 1;
2242 r0_status = sys$parse(&fab);
2243 if (r0_status == RMS$_SYN)
2245 error("File syntax error", path.c_str());
2249 if (!$VMS_STATUS_SUCCESS(r0_status))
2251 (void)lib$signal (r0_status);
2254 less[naml.naml$l_long_expand_size - naml.naml$b_ver] = '\0';
2255 sess[naml.naml$b_esl - naml.naml$b_ver] = '\0';
2256 if (naml.naml$l_long_expand_size > naml.naml$b_esl)
2258 path = decc$translate_vms (less);
2262 path = decc$translate_vms(sess);
2266 // make sure separators are correct type (Windows or Linux)
2267 for (size_t i = 0; i < path.length(); i++)
2269 i = path.find_first_of("/\\", i);
2270 if (i == string::npos)
2272 path[i] = g_fileSeparator;
2274 // remove beginning separator if requested
2275 if (removeBeginningSeparator && (path[0] == g_fileSeparator))
2279 void ASConsole::printMsg(const char* msg, const string& data) const
2283 printf(msg, data.c_str());
2286 void ASConsole::printSeparatingLine() const
2289 for (size_t i = 0; i < 60; i++)
2291 printMsg("%s\n", line);
2294 void ASConsole::printVerboseHeader() const
2303 struct tm* ptr = localtime(<);
2304 strftime(str, 20, "%x", ptr);
2306 // 60 is the length of the separator in printSeparatingLine()
2307 string header = "Artistic Style " + string(g_version);
2308 size_t numSpaces = 60 - header.length() - strlen(str);
2309 header.append(numSpaces, ' ');
2311 header.append("\n");
2312 printf("%s", header.c_str());
2313 // print options file
2314 if (!optionsFileName.empty())
2315 printf(_("Using default options file %s\n"), optionsFileName.c_str());
2318 void ASConsole::printVerboseStats(clock_t startTime) const
2324 printSeparatingLine();
2325 string formatted = getNumberFormat(filesFormatted);
2326 string unchanged = getNumberFormat(filesUnchanged);
2327 printf(_(" %s formatted %s unchanged "), formatted.c_str(), unchanged.c_str());
2329 // show processing time
2330 clock_t stopTime = clock();
2331 double secs = (stopTime - startTime) / double (CLOCKS_PER_SEC);
2335 printf("%.2f", secs);
2336 else if (secs < 20.0)
2337 printf("%.1f", secs);
2339 printf("%.0f", secs);
2340 printf("%s", _(" seconds "));
2344 // show minutes and seconds if time is greater than one minute
2345 int min = (int) secs / 60;
2347 int minsec = int (secs + .5);
2348 printf(_("%d min %d sec "), min, minsec);
2351 string lines = getNumberFormat(linesOut);
2352 printf(_("%s lines\n"), lines.c_str());
2355 void ASConsole::sleep(int seconds) const
2358 endwait = clock_t (clock () + seconds * CLOCKS_PER_SEC);
2359 while (clock() < endwait) {}
2362 bool ASConsole::stringEndsWith(const string& str, const string& suffix) const
2364 int strIndex = (int) str.length() - 1;
2365 int suffixIndex = (int) suffix.length() - 1;
2367 while (strIndex >= 0 && suffixIndex >= 0)
2369 if (tolower(str[strIndex]) != tolower(suffix[suffixIndex]))
2375 // suffix longer than string
2376 if (strIndex < 0 && suffixIndex >= 0)
2381 void ASConsole::updateExcludeVector(const string& suffixParam)
2383 excludeVector.emplace_back(suffixParam);
2384 standardizePath(excludeVector.back(), true);
2385 excludeHitsVector.push_back(false);
2388 int ASConsole::waitForRemove(const char* newFileName) const
2392 // sleep a max of 20 seconds for the remove
2393 for (seconds = 1; seconds <= 20; seconds++)
2396 if (stat(newFileName, &stBuf) != 0)
2403 // From The Code Project http://www.codeproject.com/string/wildcmp.asp
2404 // Written by Jack Handy - jakkhandy@hotmail.com
2405 // Modified to compare case insensitive for Windows
2406 int ASConsole::wildcmp(const char* wild, const char* data) const
2408 const char* cp = nullptr, *mp = nullptr;
2411 while ((*data) && (*wild != '*'))
2413 if (!g_isCaseSensitive)
2414 cmpval = (tolower(*wild) != tolower(*data)) && (*wild != '?');
2416 cmpval = (*wild != *data) && (*wild != '?');
2439 if (!g_isCaseSensitive)
2440 cmpval = (tolower(*wild) == tolower(*data) || (*wild == '?'));
2442 cmpval = (*wild == *data) || (*wild == '?');
2457 while (*wild == '*')
2464 void ASConsole::writeFile(const string& fileName_, FileEncoding encoding, ostringstream& out) const
2466 // save date accessed and date modified of original file
2468 bool statErr = false;
2469 if (stat(fileName_.c_str(), &stBuf) == -1)
2475 string origFileName = fileName_ + origSuffix;
2476 removeFile(origFileName.c_str(), "Cannot remove pre-existing backup file");
2477 renameFile(fileName_.c_str(), origFileName.c_str(), "Cannot create backup file");
2480 // write the output file
2481 ofstream fout(fileName_.c_str(), ios::binary | ios::trunc);
2483 error("Cannot open output file", fileName_.c_str());
2484 if (encoding == UTF_16LE || encoding == UTF_16BE)
2486 // convert utf-8 to utf-16
2487 bool isBigEndian = (encoding == UTF_16BE);
2488 size_t utf16Size = utf8_16.utf16LengthFromUtf8(out.str().c_str(), out.str().length());
2489 char* utf16Out = new char[utf16Size];
2490 size_t utf16Len = utf8_16.utf8ToUtf16(const_cast<char*>(out.str().c_str()),
2491 out.str().length(), isBigEndian, utf16Out);
2492 assert(utf16Len == utf16Size);
2493 fout << string(utf16Out, utf16Len);
2501 // change date modified to original file date
2502 // Embarcadero must be linked with cw32mt not cw32
2507 struct utimbuf outBuf;
2508 outBuf.actime = stBuf.st_atime;
2509 // add ticks so 'make' will recognize a change
2510 // Visual Studio 2008 needs more than 1
2511 outBuf.modtime = stBuf.st_mtime + 10;
2512 if (utime(fileName_.c_str(), &outBuf) == -1)
2517 perror("errno message");
2518 (*errorStream) << "********* Cannot preserve file date" << endl;
2525 //-----------------------------------------------------------------------------
2527 // used by shared object (DLL) calls
2528 //-----------------------------------------------------------------------------
2530 utf16_t* ASLibrary::formatUtf16(const utf16_t* pSourceIn, // the source to be formatted
2531 const utf16_t* pOptions, // AStyle options
2532 fpError fpErrorHandler, // error handler function
2533 fpAlloc fpMemoryAlloc) const // memory allocation function)
2535 const char* utf8In = convertUtf16ToUtf8(pSourceIn);
2536 if (utf8In == nullptr)
2538 fpErrorHandler(121, "Cannot convert input utf-16 to utf-8.");
2541 const char* utf8Options = convertUtf16ToUtf8(pOptions);
2542 if (utf8Options == nullptr)
2545 fpErrorHandler(122, "Cannot convert options utf-16 to utf-8.");
2548 // call the Artistic Style formatting function
2549 // cannot use the callers memory allocation here
2550 char* utf8Out = AStyleMain(utf8In,
2553 ASLibrary::tempMemoryAllocation);
2554 // finished with these
2556 delete[] utf8Options;
2558 utf8Options = nullptr;
2559 // AStyle error has already been sent
2560 if (utf8Out == nullptr)
2562 // convert text to wide char and return it
2563 utf16_t* utf16Out = convertUtf8ToUtf16(utf8Out, fpMemoryAlloc);
2566 if (utf16Out == nullptr)
2568 fpErrorHandler(123, "Cannot convert output utf-8 to utf-16.");
2574 // STATIC method to allocate temporary memory for AStyle formatting.
2575 // The data will be converted before being returned to the calling program.
2576 char* STDCALL ASLibrary::tempMemoryAllocation(unsigned long memoryNeeded)
2578 char* buffer = new (nothrow) char[memoryNeeded];
2583 * Convert utf-8 strings to utf16 strings.
2584 * Memory is allocated by the calling program memory allocation function.
2585 * The calling function must check for errors.
2587 utf16_t* ASLibrary::convertUtf8ToUtf16(const char* utf8In, fpAlloc fpMemoryAlloc) const
2589 if (utf8In == nullptr)
2591 char* data = const_cast<char*>(utf8In);
2592 size_t dataSize = strlen(utf8In);
2593 bool isBigEndian = utf8_16.getBigEndian();
2594 // return size is in number of CHARs, not utf16_t
2595 size_t utf16Size = (utf8_16.utf16LengthFromUtf8(data, dataSize) + sizeof(utf16_t));
2596 char* utf16Out = fpMemoryAlloc((long)utf16Size);
2597 if (utf16Out == nullptr)
2600 utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
2602 size_t utf16Len = utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
2603 assert(utf16Len == utf16Size);
2605 assert(utf16Size == (utf8_16.utf16len(reinterpret_cast<utf16_t*>(utf16Out)) + 1) * sizeof(utf16_t));
2606 return reinterpret_cast<utf16_t*>(utf16Out);
2610 * Convert utf16 strings to utf-8.
2611 * The calling function must check for errors and delete the
2614 char* ASLibrary::convertUtf16ToUtf8(const utf16_t* utf16In) const
2616 if (utf16In == nullptr)
2618 char* data = reinterpret_cast<char*>(const_cast<utf16_t*>(utf16In));
2619 // size must be in chars
2620 size_t dataSize = utf8_16.utf16len(utf16In) * sizeof(utf16_t);
2621 bool isBigEndian = utf8_16.getBigEndian();
2622 size_t utf8Size = utf8_16.utf8LengthFromUtf16(data, dataSize, isBigEndian) + 1;
2623 char* utf8Out = new (nothrow) char[utf8Size];
2624 if (utf8Out == nullptr)
2627 utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
2629 size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
2630 assert(utf8Len == utf8Size);
2632 assert(utf8Size == strlen(utf8Out) + 1);
2636 #endif // ASTYLE_LIB
2638 //-----------------------------------------------------------------------------
2640 // used by both console and library builds
2641 //-----------------------------------------------------------------------------
2644 ASOptions::ASOptions(ASFormatter& formatterArg)
2645 : formatter(formatterArg)
2648 ASOptions::ASOptions(ASFormatter& formatterArg, ASConsole& consoleArg)
2649 : formatter(formatterArg), console(consoleArg)
2654 * parse the options vector
2655 * optionsVector can be either a fileOptionsVector (options file) or an optionsVector (command line)
2657 * @return true if no errors, false if errors
2659 bool ASOptions::parseOptions(vector<string>& optionsVector, const string& errorInfo)
2661 vector<string>::iterator option;
2663 optionErrors.clear();
2665 for (option = optionsVector.begin(); option != optionsVector.end(); ++option)
2669 if (arg.compare(0, 2, "--") == 0)
2670 parseOption(arg.substr(2), errorInfo);
2671 else if (arg[0] == '-')
2675 for (i = 1; i < arg.length(); ++i)
2678 && isalpha((unsigned char)arg[i])
2679 && arg[i - 1] != 'x')
2681 // parse the previous option in subArg
2682 parseOption(subArg, errorInfo);
2685 // append the current option to subArg
2686 subArg.append(1, arg[i]);
2688 // parse the last option
2689 parseOption(subArg, errorInfo);
2694 parseOption(arg, errorInfo);
2698 if (optionErrors.str().length() > 0)
2703 void ASOptions::parseOption(const string& arg, const string& errorInfo)
2705 if ( isOption(arg, "style=allman") || isOption(arg, "style=bsd") || isOption(arg, "style=break") )
2707 formatter.setFormattingStyle(STYLE_ALLMAN);
2709 else if ( isOption(arg, "style=java") || isOption(arg, "style=attach") )
2711 formatter.setFormattingStyle(STYLE_JAVA);
2713 else if ( isOption(arg, "style=k&r") || isOption(arg, "style=kr") || isOption(arg, "style=k/r") )
2715 formatter.setFormattingStyle(STYLE_KR);
2717 else if ( isOption(arg, "style=stroustrup") )
2719 formatter.setFormattingStyle(STYLE_STROUSTRUP);
2721 else if ( isOption(arg, "style=whitesmith") )
2723 formatter.setFormattingStyle(STYLE_WHITESMITH);
2725 else if ( isOption(arg, "style=vtk") )
2727 formatter.setFormattingStyle(STYLE_VTK);
2729 else if ( isOption(arg, "style=banner") )
2731 formatter.setFormattingStyle(STYLE_BANNER);
2733 else if ( isOption(arg, "style=gnu") )
2735 formatter.setFormattingStyle(STYLE_GNU);
2737 else if ( isOption(arg, "style=linux") || isOption(arg, "style=knf") )
2739 formatter.setFormattingStyle(STYLE_LINUX);
2741 else if ( isOption(arg, "style=horstmann") || isOption(arg, "style=run-in") )
2743 formatter.setFormattingStyle(STYLE_HORSTMANN);
2745 else if ( isOption(arg, "style=1tbs") || isOption(arg, "style=otbs") )
2747 formatter.setFormattingStyle(STYLE_1TBS);
2749 else if ( isOption(arg, "style=google") )
2751 formatter.setFormattingStyle(STYLE_GOOGLE);
2753 else if (isOption(arg, "style=mozilla"))
2755 formatter.setFormattingStyle(STYLE_MOZILLA);
2757 else if ( isOption(arg, "style=pico") )
2759 formatter.setFormattingStyle(STYLE_PICO);
2761 else if ( isOption(arg, "style=lisp") || isOption(arg, "style=python") )
2763 formatter.setFormattingStyle(STYLE_LISP);
2765 else if ( isParamOption(arg, "A") )
2768 string styleParam = getParam(arg, "A");
2769 if (styleParam.length() > 0)
2770 style = atoi(styleParam.c_str());
2772 formatter.setFormattingStyle(STYLE_ALLMAN);
2773 else if (style == 2)
2774 formatter.setFormattingStyle(STYLE_JAVA);
2775 else if (style == 3)
2776 formatter.setFormattingStyle(STYLE_KR);
2777 else if (style == 4)
2778 formatter.setFormattingStyle(STYLE_STROUSTRUP);
2779 else if (style == 5)
2780 formatter.setFormattingStyle(STYLE_WHITESMITH);
2781 else if (style == 6)
2782 formatter.setFormattingStyle(STYLE_BANNER);
2783 else if (style == 7)
2784 formatter.setFormattingStyle(STYLE_GNU);
2785 else if (style == 8)
2786 formatter.setFormattingStyle(STYLE_LINUX);
2787 else if (style == 9)
2788 formatter.setFormattingStyle(STYLE_HORSTMANN);
2789 else if (style == 10)
2790 formatter.setFormattingStyle(STYLE_1TBS);
2791 else if (style == 11)
2792 formatter.setFormattingStyle(STYLE_PICO);
2793 else if (style == 12)
2794 formatter.setFormattingStyle(STYLE_LISP);
2795 else if (style == 14)
2796 formatter.setFormattingStyle(STYLE_GOOGLE);
2797 else if (style == 15)
2798 formatter.setFormattingStyle(STYLE_VTK);
2799 else if (style == 16)
2800 formatter.setFormattingStyle(STYLE_MOZILLA);
2802 isOptionError(arg, errorInfo);
2804 // must check for mode=cs before mode=c !!!
2805 else if ( isOption(arg, "mode=cs") )
2807 formatter.setSharpStyle();
2808 formatter.setModeManuallySet(true);
2810 else if ( isOption(arg, "mode=c") )
2812 formatter.setCStyle();
2813 formatter.setModeManuallySet(true);
2815 else if ( isOption(arg, "mode=java") )
2817 formatter.setJavaStyle();
2818 formatter.setModeManuallySet(true);
2820 else if ( isParamOption(arg, "t", "indent=tab=") )
2823 string spaceNumParam = getParam(arg, "t", "indent=tab=");
2824 if (spaceNumParam.length() > 0)
2825 spaceNum = atoi(spaceNumParam.c_str());
2826 if (spaceNum < 2 || spaceNum > 20)
2827 isOptionError(arg, errorInfo);
2830 formatter.setTabIndentation(spaceNum, false);
2833 else if ( isOption(arg, "indent=tab") )
2835 formatter.setTabIndentation(4);
2837 else if ( isParamOption(arg, "T", "indent=force-tab=") )
2840 string spaceNumParam = getParam(arg, "T", "indent=force-tab=");
2841 if (spaceNumParam.length() > 0)
2842 spaceNum = atoi(spaceNumParam.c_str());
2843 if (spaceNum < 2 || spaceNum > 20)
2844 isOptionError(arg, errorInfo);
2847 formatter.setTabIndentation(spaceNum, true);
2850 else if ( isOption(arg, "indent=force-tab") )
2852 formatter.setTabIndentation(4, true);
2854 else if ( isParamOption(arg, "xT", "indent=force-tab-x=") )
2857 string tabNumParam = getParam(arg, "xT", "indent=force-tab-x=");
2858 if (tabNumParam.length() > 0)
2859 tabNum = atoi(tabNumParam.c_str());
2860 if (tabNum < 2 || tabNum > 20)
2861 isOptionError(arg, errorInfo);
2864 formatter.setForceTabXIndentation(tabNum);
2867 else if ( isOption(arg, "indent=force-tab-x") )
2869 formatter.setForceTabXIndentation(8);
2871 else if ( isParamOption(arg, "s", "indent=spaces=") )
2874 string spaceNumParam = getParam(arg, "s", "indent=spaces=");
2875 if (spaceNumParam.length() > 0)
2876 spaceNum = atoi(spaceNumParam.c_str());
2877 if (spaceNum < 2 || spaceNum > 20)
2878 isOptionError(arg, errorInfo);
2881 formatter.setSpaceIndentation(spaceNum);
2884 else if ( isOption(arg, "indent=spaces") )
2886 formatter.setSpaceIndentation(4);
2888 else if (isParamOption(arg, "xt", "indent-continuation="))
2891 string contIndentParam = getParam(arg, "xt", "indent-continuation=");
2892 if (contIndentParam.length() > 0)
2893 contIndent = atoi(contIndentParam.c_str());
2895 isOptionError(arg, errorInfo);
2896 else if (contIndent > 4)
2897 isOptionError(arg, errorInfo);
2899 formatter.setContinuationIndentation(contIndent);
2901 else if ( isParamOption(arg, "m", "min-conditional-indent=") )
2903 int minIndent = MINCOND_TWO;
2904 string minIndentParam = getParam(arg, "m", "min-conditional-indent=");
2905 if (minIndentParam.length() > 0)
2906 minIndent = atoi(minIndentParam.c_str());
2907 if (minIndent >= MINCOND_END)
2908 isOptionError(arg, errorInfo);
2910 formatter.setMinConditionalIndentOption(minIndent);
2912 else if ( isParamOption(arg, "M", "max-continuation-indent=") )
2915 string maxIndentParam = getParam(arg, "M", "max-continuation-indent=");
2916 if (maxIndentParam.length() > 0)
2917 maxIndent = atoi(maxIndentParam.c_str());
2919 isOptionError(arg, errorInfo);
2920 else if (maxIndent > 120)
2921 isOptionError(arg, errorInfo);
2923 formatter.setMaxContinuationIndentLength(maxIndent);
2925 else if ( isOption(arg, "N", "indent-namespaces") )
2927 formatter.setNamespaceIndent(true);
2929 else if ( isOption(arg, "C", "indent-classes") )
2931 formatter.setClassIndent(true);
2933 else if ( isOption(arg, "xG", "indent-modifiers") )
2935 formatter.setModifierIndent(true);
2937 else if ( isOption(arg, "S", "indent-switches") )
2939 formatter.setSwitchIndent(true);
2941 else if ( isOption(arg, "K", "indent-cases") )
2943 formatter.setCaseIndent(true);
2945 else if ( isOption(arg, "xU", "indent-after-parens") )
2947 formatter.setAfterParenIndent(true);
2949 else if ( isOption(arg, "L", "indent-labels") )
2951 formatter.setLabelIndent(true);
2953 else if (isOption(arg, "xW", "indent-preproc-block"))
2955 formatter.setPreprocBlockIndent(true);
2957 else if ( isOption(arg, "w", "indent-preproc-define") )
2959 formatter.setPreprocDefineIndent(true);
2961 else if ( isOption(arg, "xw", "indent-preproc-cond") )
2963 formatter.setPreprocConditionalIndent(true);
2965 else if ( isOption(arg, "y", "break-closing-braces") )
2967 formatter.setBreakClosingHeaderBracesMode(true);
2969 else if ( isOption(arg, "O", "keep-one-line-blocks") )
2971 formatter.setBreakOneLineBlocksMode(false);
2973 else if ( isOption(arg, "o", "keep-one-line-statements") )
2975 formatter.setBreakOneLineStatementsMode(false);
2977 else if ( isOption(arg, "P", "pad-paren") )
2979 formatter.setParensOutsidePaddingMode(true);
2980 formatter.setParensInsidePaddingMode(true);
2982 else if ( isOption(arg, "d", "pad-paren-out") )
2984 formatter.setParensOutsidePaddingMode(true);
2986 else if ( isOption(arg, "xd", "pad-first-paren-out") )
2988 formatter.setParensFirstPaddingMode(true);
2990 else if ( isOption(arg, "D", "pad-paren-in") )
2992 formatter.setParensInsidePaddingMode(true);
2994 else if ( isOption(arg, "H", "pad-header") )
2996 formatter.setParensHeaderPaddingMode(true);
2998 else if ( isOption(arg, "U", "unpad-paren") )
3000 formatter.setParensUnPaddingMode(true);
3002 else if ( isOption(arg, "p", "pad-oper") )
3004 formatter.setOperatorPaddingMode(true);
3006 else if (isOption(arg, "xg", "pad-comma"))
3008 formatter.setCommaPaddingMode(true);
3010 else if ( isOption(arg, "xe", "delete-empty-lines") )
3012 formatter.setDeleteEmptyLinesMode(true);
3014 else if ( isOption(arg, "E", "fill-empty-lines") )
3016 formatter.setEmptyLineFill(true);
3018 else if ( isOption(arg, "c", "convert-tabs") )
3020 formatter.setTabSpaceConversionMode(true);
3022 else if ( isOption(arg, "xy", "close-templates") )
3024 formatter.setCloseTemplatesMode(true);
3026 else if ( isOption(arg, "F", "break-blocks=all") )
3028 formatter.setBreakBlocksMode(true);
3029 formatter.setBreakClosingHeaderBlocksMode(true);
3031 else if ( isOption(arg, "f", "break-blocks") )
3033 formatter.setBreakBlocksMode(true);
3035 else if ( isOption(arg, "e", "break-elseifs") )
3037 formatter.setBreakElseIfsMode(true);
3039 else if ( isOption(arg, "xb", "break-one-line-headers") )
3041 formatter.setBreakOneLineHeadersMode(true);
3043 else if ( isOption(arg, "j", "add-braces") )
3045 formatter.setAddBracesMode(true);
3047 else if ( isOption(arg, "J", "add-one-line-braces") )
3049 formatter.setAddOneLineBracesMode(true);
3051 else if ( isOption(arg, "xj", "remove-braces") )
3053 formatter.setRemoveBracesMode(true);
3055 else if ( isOption(arg, "Y", "indent-col1-comments") )
3057 formatter.setIndentCol1CommentsMode(true);
3059 else if ( isOption(arg, "align-pointer=type") )
3061 formatter.setPointerAlignment(PTR_ALIGN_TYPE);
3063 else if ( isOption(arg, "align-pointer=middle") )
3065 formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
3067 else if ( isOption(arg, "align-pointer=name") )
3069 formatter.setPointerAlignment(PTR_ALIGN_NAME);
3071 else if ( isParamOption(arg, "k") )
3074 string styleParam = getParam(arg, "k");
3075 if (styleParam.length() > 0)
3076 align = atoi(styleParam.c_str());
3077 if (align < 1 || align > 3)
3078 isOptionError(arg, errorInfo);
3079 else if (align == 1)
3080 formatter.setPointerAlignment(PTR_ALIGN_TYPE);
3081 else if (align == 2)
3082 formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
3083 else if (align == 3)
3084 formatter.setPointerAlignment(PTR_ALIGN_NAME);
3086 else if ( isOption(arg, "align-reference=none") )
3088 formatter.setReferenceAlignment(REF_ALIGN_NONE);
3090 else if ( isOption(arg, "align-reference=type") )
3092 formatter.setReferenceAlignment(REF_ALIGN_TYPE);
3094 else if ( isOption(arg, "align-reference=middle") )
3096 formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
3098 else if ( isOption(arg, "align-reference=name") )
3100 formatter.setReferenceAlignment(REF_ALIGN_NAME);
3102 else if ( isParamOption(arg, "W") )
3105 string styleParam = getParam(arg, "W");
3106 if (styleParam.length() > 0)
3107 align = atoi(styleParam.c_str());
3108 if (align < 0 || align > 3)
3109 isOptionError(arg, errorInfo);
3110 else if (align == 0)
3111 formatter.setReferenceAlignment(REF_ALIGN_NONE);
3112 else if (align == 1)
3113 formatter.setReferenceAlignment(REF_ALIGN_TYPE);
3114 else if (align == 2)
3115 formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
3116 else if (align == 3)
3117 formatter.setReferenceAlignment(REF_ALIGN_NAME);
3119 else if ( isParamOption(arg, "max-code-length=") )
3122 string maxLengthParam = getParam(arg, "max-code-length=");
3123 if (maxLengthParam.length() > 0)
3124 maxLength = atoi(maxLengthParam.c_str());
3126 isOptionError(arg, errorInfo);
3127 else if (maxLength > 200)
3128 isOptionError(arg, errorInfo);
3130 formatter.setMaxCodeLength(maxLength);
3132 else if ( isParamOption(arg, "xC") )
3135 string maxLengthParam = getParam(arg, "xC");
3136 if (maxLengthParam.length() > 0)
3137 maxLength = atoi(maxLengthParam.c_str());
3138 if (maxLength > 200)
3139 isOptionError(arg, errorInfo);
3141 formatter.setMaxCodeLength(maxLength);
3143 else if ( isOption(arg, "xL", "break-after-logical") )
3145 formatter.setBreakAfterMode(true);
3147 else if ( isOption(arg, "xc", "attach-classes") )
3149 formatter.setAttachClass(true);
3151 else if ( isOption(arg, "xV", "attach-closing-while") )
3153 formatter.setAttachClosingWhile(true);
3155 else if ( isOption(arg, "xk", "attach-extern-c") )
3157 formatter.setAttachExternC(true);
3159 else if ( isOption(arg, "xn", "attach-namespaces") )
3161 formatter.setAttachNamespace(true);
3163 else if ( isOption(arg, "xl", "attach-inlines") )
3165 formatter.setAttachInline(true);
3167 else if ( isOption(arg, "xp", "remove-comment-prefix") )
3169 formatter.setStripCommentPrefix(true);
3171 // Objective-C options
3172 else if ( isOption(arg, "xQ", "pad-method-prefix") )
3174 formatter.setMethodPrefixPaddingMode(true);
3176 else if ( isOption(arg, "xR", "unpad-method-prefix") )
3178 formatter.setMethodPrefixUnPaddingMode(true);
3180 else if (isOption(arg, "xq", "pad-return-type"))
3182 formatter.setReturnTypePaddingMode(true);
3184 else if (isOption(arg, "xr", "unpad-return-type"))
3186 formatter.setReturnTypeUnPaddingMode(true);
3188 else if (isOption(arg, "xS", "pad-param-type"))
3190 formatter.setParamTypePaddingMode(true);
3192 else if (isOption(arg, "xs", "unpad-param-type"))
3194 formatter.setParamTypeUnPaddingMode(true);
3196 else if (isOption(arg, "xM", "align-method-colon"))
3198 formatter.setAlignMethodColon(true);
3200 else if ( isOption(arg, "xP0", "pad-method-colon=none") )
3202 formatter.setObjCColonPaddingMode(COLON_PAD_NONE);
3204 else if ( isOption(arg, "xP1", "pad-method-colon=all") )
3206 formatter.setObjCColonPaddingMode(COLON_PAD_ALL);
3208 else if ( isOption(arg, "xP2", "pad-method-colon=after") )
3210 formatter.setObjCColonPaddingMode(COLON_PAD_AFTER);
3212 else if ( isOption(arg, "xP3", "pad-method-colon=before") )
3214 formatter.setObjCColonPaddingMode(COLON_PAD_BEFORE);
3216 // depreciated options ////////////////////////////////////////////////////////////////////////
3217 else if ( isOption(arg, "indent-preprocessor") ) // depreciated release 2.04
3219 formatter.setPreprocDefineIndent(true);
3221 else if ( isOption(arg, "style=ansi") ) // depreciated release 2.05
3223 formatter.setFormattingStyle(STYLE_ALLMAN);
3225 // depreciated in release 3.0 /////////////////////////////////////////////////////////////////
3226 else if ( isOption(arg, "break-closing-brackets") ) // depreciated release 3.0
3228 formatter.setBreakClosingHeaderBracketsMode(true);
3230 else if ( isOption(arg, "add-brackets") ) // depreciated release 3.0
3232 formatter.setAddBracketsMode(true);
3234 else if ( isOption(arg, "add-one-line-brackets") ) // depreciated release 3.0
3236 formatter.setAddOneLineBracketsMode(true);
3238 else if ( isOption(arg, "remove-brackets") ) // depreciated release 3.0
3240 formatter.setRemoveBracketsMode(true);
3242 else if ( isParamOption(arg, "max-instatement-indent=") ) // depreciated release 3.0
3245 string maxIndentParam = getParam(arg, "max-instatement-indent=");
3246 if (maxIndentParam.length() > 0)
3247 maxIndent = atoi(maxIndentParam.c_str());
3249 isOptionError(arg, errorInfo);
3250 else if (maxIndent > 120)
3251 isOptionError(arg, errorInfo);
3253 formatter.setMaxInStatementIndentLength(maxIndent);
3255 // NOTE: Removed in release 2.04.
3256 // else if ( isOption(arg, "b", "brackets=break") )
3258 // formatter.setBracketFormatMode(BREAK_MODE);
3260 // else if ( isOption(arg, "a", "brackets=attach") )
3262 // formatter.setBracketFormatMode(ATTACH_MODE);
3264 // else if ( isOption(arg, "l", "brackets=linux") )
3266 // formatter.setBracketFormatMode(LINUX_MODE);
3268 // else if ( isOption(arg, "u", "brackets=stroustrup") )
3270 // formatter.setBracketFormatMode(STROUSTRUP_MODE);
3272 // else if ( isOption(arg, "g", "brackets=run-in") )
3274 // formatter.setBracketFormatMode(RUN_IN_MODE);
3276 // end depreciated options ////////////////////////////////////////////////////////////////////
3278 // End of options used by GUI /////////////////////////////////////////////////////////////////
3280 isOptionError(arg, errorInfo);
3282 // Options used by only console ///////////////////////////////////////////////////////////////
3283 else if ( isOption(arg, "n", "suffix=none") )
3285 console.setNoBackup(true);
3287 else if ( isParamOption(arg, "suffix=") )
3289 string suffixParam = getParam(arg, "suffix=");
3290 if (suffixParam.length() > 0)
3292 console.setOrigSuffix(suffixParam);
3295 else if ( isParamOption(arg, "exclude=") )
3297 string suffixParam = getParam(arg, "exclude=");
3298 if (suffixParam.length() > 0)
3299 console.updateExcludeVector(suffixParam);
3301 else if ( isOption(arg, "r", "R") || isOption(arg, "recursive") )
3303 console.setIsRecursive(true);
3305 else if (isOption(arg, "dry-run"))
3307 console.setIsDryRun(true);
3309 else if ( isOption(arg, "Z", "preserve-date") )
3311 console.setPreserveDate(true);
3313 else if ( isOption(arg, "v", "verbose") )
3315 console.setIsVerbose(true);
3317 else if ( isOption(arg, "Q", "formatted") )
3319 console.setIsFormattedOnly(true);
3321 else if ( isOption(arg, "q", "quiet") )
3323 console.setIsQuiet(true);
3325 else if ( isOption(arg, "i", "ignore-exclude-errors") )
3327 console.setIgnoreExcludeErrors(true);
3329 else if ( isOption(arg, "xi", "ignore-exclude-errors-x") )
3331 console.setIgnoreExcludeErrorsAndDisplay(true);
3333 else if ( isOption(arg, "X", "errors-to-stdout") )
3335 console.setErrorStream(&cout);
3337 else if ( isOption(arg, "lineend=windows") )
3339 formatter.setLineEndFormat(LINEEND_WINDOWS);
3341 else if ( isOption(arg, "lineend=linux") )
3343 formatter.setLineEndFormat(LINEEND_LINUX);
3345 else if ( isOption(arg, "lineend=macold") )
3347 formatter.setLineEndFormat(LINEEND_MACOLD);
3349 else if ( isParamOption(arg, "z") )
3351 int lineendType = 0;
3352 string lineendParam = getParam(arg, "z");
3353 if (lineendParam.length() > 0)
3354 lineendType = atoi(lineendParam.c_str());
3355 if (lineendType < 1 || lineendType > 3)
3356 isOptionError(arg, errorInfo);
3357 else if (lineendType == 1)
3358 formatter.setLineEndFormat(LINEEND_WINDOWS);
3359 else if (lineendType == 2)
3360 formatter.setLineEndFormat(LINEEND_LINUX);
3361 else if (lineendType == 3)
3362 formatter.setLineEndFormat(LINEEND_MACOLD);
3364 else if ( isParamOption(arg, "stdin=") )
3366 string path = getParam(arg, "stdin=");
3367 console.standardizePath(path);
3368 console.setStdPathIn(path);
3370 else if ( isParamOption(arg, "stdout=") )
3372 string path = getParam(arg, "stdout=");
3373 console.standardizePath(path);
3374 console.setStdPathOut(path);
3377 isOptionError(arg, errorInfo);
3379 } // End of parseOption function
3381 // Parse options from the options file.
3382 void ASOptions::importOptions(istream& in, vector<string>& optionsVector)
3385 bool isInQuote = false;
3386 char quoteChar = ' ';
3387 string currentToken;
3397 // treat '#' as line comments
3402 if (ch == '\n' || ch == '\r')
3406 // break options on new-lines, tabs, commas, or spaces
3407 // remove quotes from output
3408 if (in.eof() || ch == '\n' || ch == '\r' || ch == '\t' || ch == ',')
3410 if (ch == ' ' && !isInQuote)
3412 if (ch == quoteChar && isInQuote)
3414 if (ch == '"' || ch == '\'')
3420 currentToken.append(1, ch);
3424 if (currentToken.length() != 0)
3425 optionsVector.emplace_back(currentToken);
3430 string ASOptions::getOptionErrors() const
3432 return optionErrors.str();
3435 string ASOptions::getParam(const string& arg, const char* op)
3437 return arg.substr(strlen(op));
3440 string ASOptions::getParam(const string& arg, const char* op1, const char* op2)
3442 return isParamOption(arg, op1) ? getParam(arg, op1) : getParam(arg, op2);
3445 bool ASOptions::isOption(const string& arg, const char* op)
3447 return arg.compare(op) == 0;
3450 bool ASOptions::isOption(const string& arg, const char* op1, const char* op2)
3452 return (isOption(arg, op1) || isOption(arg, op2));
3455 void ASOptions::isOptionError(const string& arg, const string& errorInfo)
3457 if (optionErrors.str().length() == 0)
3458 optionErrors << errorInfo << endl; // need main error message
3459 optionErrors << arg << endl;
3462 bool ASOptions::isParamOption(const string& arg, const char* option)
3464 bool retVal = arg.compare(0, strlen(option), option) == 0;
3465 // if comparing for short option, 2nd char of arg must be numeric
3466 if (retVal && strlen(option) == 1 && arg.length() > 1)
3467 if (!isdigit((unsigned char)arg[1]))
3472 bool ASOptions::isParamOption(const string& arg, const char* option1, const char* option2)
3474 return isParamOption(arg, option1) || isParamOption(arg, option2);
3477 //----------------------------------------------------------------------------
3479 //----------------------------------------------------------------------------
3481 // Return true if an int is big endian.
3482 bool ASEncoding::getBigEndian() const
3484 short int word = 0x0001;
3485 char* byte = (char*) &word;
3486 return (byte[0] ? false : true);
3489 // Swap the two low order bytes of a 16 bit integer value.
3490 int ASEncoding::swap16bit(int value) const
3492 return ( ((value & 0xff) << 8) | ((value & 0xff00) >> 8) );
3495 // Return the length of a utf-16 C string.
3496 // The length is in number of utf16_t.
3497 size_t ASEncoding::utf16len(const utf16* utf16In) const
3500 while (*utf16In++ != '\0')
3505 // Adapted from SciTE UniConversion.cxx.
3506 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
3507 // Modified for Artistic Style by Jim Pattee.
3508 // Compute the length of an output utf-8 file given a utf-16 file.
3509 // Input inLen is the size in BYTES (not wchar_t).
3510 size_t ASEncoding::utf8LengthFromUtf16(const char* utf16In, size_t inLen, bool isBigEndian) const
3513 size_t wcharLen = inLen / 2;
3514 const short* uptr = reinterpret_cast<const short*>(utf16In);
3515 for (size_t i = 0; i < wcharLen && uptr[i];)
3517 size_t uch = isBigEndian ? swap16bit(uptr[i]) : uptr[i];
3520 else if (uch < 0x800)
3522 else if ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_TRAIL_LAST))
3534 // Adapted from SciTE Utf8_16.cxx.
3535 // Copyright (C) 2002 Scott Kirkwood.
3536 // Modified for Artistic Style by Jim Pattee.
3537 // Convert a utf-8 file to utf-16.
3538 size_t ASEncoding::utf8ToUtf16(char* utf8In, size_t inLen, bool isBigEndian, char* utf16Out) const
3541 ubyte* pRead = reinterpret_cast<ubyte*>(utf8In);
3542 utf16* pCur = reinterpret_cast<utf16*>(utf16Out);
3543 const ubyte* pEnd = pRead + inLen;
3544 const utf16* pCurStart = pCur;
3545 eState state = eStart;
3547 // the BOM will automatically be converted to utf-16
3548 while (pRead < pEnd)
3553 if ((0xF0 & *pRead) == 0xF0)
3555 nCur = (0x7 & *pRead) << 18;
3556 state = eSecondOf4Bytes;
3558 else if ((0xE0 & *pRead) == 0xE0)
3560 nCur = (~0xE0 & *pRead) << 12;
3561 state = ePenultimate;
3563 else if ((0xC0 & *pRead) == 0xC0)
3565 nCur = (~0xC0 & *pRead) << 6;
3574 case eSecondOf4Bytes:
3575 nCur |= (0x3F & *pRead) << 12;
3576 state = ePenultimate;
3579 nCur |= (0x3F & *pRead) << 6;
3583 nCur |= (0x3F & *pRead);
3586 // no default case is needed
3590 if (state == eStart)
3592 int codePoint = nCur;
3593 if (codePoint >= SURROGATE_FIRST_VALUE)
3595 codePoint -= SURROGATE_FIRST_VALUE;
3596 int lead = (codePoint >> 10) + SURROGATE_LEAD_FIRST;
3597 *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(lead) : lead);
3598 int trail = (codePoint & 0x3ff) + SURROGATE_TRAIL_FIRST;
3599 *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(trail) : trail);
3602 *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(codePoint) : codePoint);
3605 // return value is the output length in BYTES (not wchar_t)
3606 return (pCur - pCurStart) * 2;
3609 // Adapted from SciTE UniConversion.cxx.
3610 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
3611 // Modified for Artistic Style by Jim Pattee.
3612 // Compute the length of an output utf-16 file given a utf-8 file.
3613 // Return value is the size in BYTES (not wchar_t).
3614 size_t ASEncoding::utf16LengthFromUtf8(const char* utf8In, size_t len) const
3618 for (size_t i = 0; i < len;)
3620 unsigned char ch = static_cast<unsigned char>(utf8In[i]);
3623 else if (ch < 0x80 + 0x40 + 0x20)
3625 else if (ch < 0x80 + 0x40 + 0x20 + 0x10)
3635 // return value is the length in bytes (not wchar_t)
3639 // Adapted from SciTE Utf8_16.cxx.
3640 // Copyright (C) 2002 Scott Kirkwood.
3641 // Modified for Artistic Style by Jim Pattee.
3642 // Convert a utf-16 file to utf-8.
3643 size_t ASEncoding::utf16ToUtf8(char* utf16In, size_t inLen, bool isBigEndian,
3644 bool firstBlock, char* utf8Out) const
3648 ubyte* pRead = reinterpret_cast<ubyte*>(utf16In);
3649 ubyte* pCur = reinterpret_cast<ubyte*>(utf8Out);
3650 const ubyte* pEnd = pRead + inLen;
3651 const ubyte* pCurStart = pCur;
3652 static eState state = eStart; // state is retained for subsequent blocks
3656 // the BOM will automatically be converted to utf-8
3657 while (pRead < pEnd)
3669 nCur16 = static_cast<utf16>(*pRead++ << 8);
3670 nCur16 |= static_cast<utf16>(*pRead);
3675 nCur16 |= static_cast<utf16>(*pRead << 8);
3677 if (nCur16 >= SURROGATE_LEAD_FIRST && nCur16 <= SURROGATE_LEAD_LAST)
3683 trail = static_cast<utf16>(*pRead++ << 8);
3684 trail |= static_cast<utf16>(*pRead);
3689 trail |= static_cast<utf16>(*pRead << 8);
3691 nCur16 = (((nCur16 & 0x3ff) << 10) | (trail & 0x3ff)) + SURROGATE_FIRST_VALUE;
3697 nCur = static_cast<ubyte>(nCur16 & 0xFF);
3700 else if (nCur16 < 0x800)
3702 nCur = static_cast<ubyte>(0xC0 | (nCur16 >> 6));
3705 else if (nCur16 < SURROGATE_FIRST_VALUE)
3707 nCur = static_cast<ubyte>(0xE0 | (nCur16 >> 12));
3708 state = ePenultimate;
3712 nCur = static_cast<ubyte>(0xF0 | (nCur16 >> 18));
3713 state = eSecondOf4Bytes;
3716 case eSecondOf4Bytes:
3717 nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 12) & 0x3F));
3718 state = ePenultimate;
3721 nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 6) & 0x3F));
3725 nCur = static_cast<ubyte>(0x80 | (nCur16 & 0x3F));
3728 // no default case is needed
3730 *pCur++ = static_cast<ubyte>(nCur);
3732 return pCur - pCurStart;
3735 //----------------------------------------------------------------------------
3737 } // namespace astyle
3739 //----------------------------------------------------------------------------
3741 using namespace astyle;
3743 //----------------------------------------------------------------------------
3744 // ASTYLE_JNI functions for Java library builds
3745 //----------------------------------------------------------------------------
3749 // called by a java program to get the version number
3750 // the function name is constructed from method names in the calling java program
3752 jstring STDCALL Java_AStyleInterface_AStyleGetVersion(JNIEnv* env, jclass)
3754 return env->NewStringUTF(g_version);
3757 // called by a java program to format the source code
3758 // the function name is constructed from method names in the calling java program
3760 jstring STDCALL Java_AStyleInterface_AStyleMain(JNIEnv* env,
3763 jstring optionsJava)
3765 g_env = env; // make object available globally
3766 g_obj = obj; // make object available globally
3768 jstring textErr = env->NewStringUTF(""); // zero length text returned if an error occurs
3770 // get the method ID
3771 jclass cls = env->GetObjectClass(obj);
3772 g_mid = env->GetMethodID(cls, "ErrorHandler", "(ILjava/lang/String;)V");
3773 if (g_mid == nullptr)
3775 cout << "Cannot find java method ErrorHandler" << endl;
3779 // convert jstring to char*
3780 const char* textIn = env->GetStringUTFChars(textInJava, nullptr);
3781 const char* options = env->GetStringUTFChars(optionsJava, nullptr);
3783 // call the C++ formatting function
3784 char* textOut = AStyleMain(textIn, options, javaErrorHandler, javaMemoryAlloc);
3785 // if an error message occurred it was displayed by errorHandler
3786 if (textOut == nullptr)
3790 jstring textOutJava = env->NewStringUTF(textOut);
3792 env->ReleaseStringUTFChars(textInJava, textIn);
3793 env->ReleaseStringUTFChars(optionsJava, options);
3798 // Call the Java error handler
3799 void STDCALL javaErrorHandler(int errorNumber, const char* errorMessage)
3801 jstring errorMessageJava = g_env->NewStringUTF(errorMessage);
3802 g_env->CallVoidMethod(g_obj, g_mid, errorNumber, errorMessageJava);
3805 // Allocate memory for the formatted text
3806 char* STDCALL javaMemoryAlloc(unsigned long memoryNeeded)
3808 // error condition is checked after return from AStyleMain
3809 char* buffer = new (nothrow) char[memoryNeeded];
3813 #endif // ASTYLE_JNI
3815 //----------------------------------------------------------------------------
3816 // ASTYLE_LIB functions for library builds
3817 //----------------------------------------------------------------------------
3821 //----------------------------------------------------------------------------
3822 // ASTYLE_LIB entry point for AStyleMainUtf16 library builds
3823 //----------------------------------------------------------------------------
3825 * IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
3826 * /EXPORT:AStyleMain=_AStyleMain@16
3827 * /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
3828 * /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
3829 * No /EXPORT is required for x64
3831 extern "C" EXPORT utf16_t* STDCALL AStyleMainUtf16(const utf16_t* pSourceIn, // the source to be formatted
3832 const utf16_t* pOptions, // AStyle options
3833 fpError fpErrorHandler, // error handler function
3834 fpAlloc fpMemoryAlloc) // memory allocation function
3836 if (fpErrorHandler == nullptr) // cannot display a message if no error handler
3839 if (pSourceIn == nullptr)
3841 fpErrorHandler(101, "No pointer to source input.");
3844 if (pOptions == nullptr)
3846 fpErrorHandler(102, "No pointer to AStyle options.");
3849 if (fpMemoryAlloc == nullptr)
3851 fpErrorHandler(103, "No pointer to memory allocation function.");
3855 // check size of utf16_t on Linux
3857 if (sizeof(utf16_t) != sizeCheck)
3859 fpErrorHandler(104, "Unsigned short is not the correct size.");
3865 utf16_t* utf16Out = library.formatUtf16(pSourceIn, pOptions, fpErrorHandler, fpMemoryAlloc);
3869 //----------------------------------------------------------------------------
3870 // ASTYLE_LIB entry point for library builds
3871 //----------------------------------------------------------------------------
3873 * IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
3874 * /EXPORT:AStyleMain=_AStyleMain@16
3875 * /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
3876 * /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
3877 * No /EXPORT is required for x64
3879 extern "C" EXPORT char* STDCALL AStyleMain(const char* pSourceIn, // the source to be formatted
3880 const char* pOptions, // AStyle options
3881 fpError fpErrorHandler, // error handler function
3882 fpAlloc fpMemoryAlloc) // memory allocation function
3884 if (fpErrorHandler == nullptr) // cannot display a message if no error handler
3887 if (pSourceIn == nullptr)
3889 fpErrorHandler(101, "No pointer to source input.");
3892 if (pOptions == nullptr)
3894 fpErrorHandler(102, "No pointer to AStyle options.");
3897 if (fpMemoryAlloc == nullptr)
3899 fpErrorHandler(103, "No pointer to memory allocation function.");
3903 ASFormatter formatter;
3904 ASOptions options(formatter);
3906 vector<string> optionsVector;
3907 istringstream opt(pOptions);
3909 options.importOptions(opt, optionsVector);
3911 bool ok = options.parseOptions(optionsVector, "Invalid Artistic Style options:");
3913 fpErrorHandler(130, options.getOptionErrors().c_str());
3915 istringstream in(pSourceIn);
3916 ASStreamIterator<istringstream> streamIterator(&in);
3918 formatter.init(&streamIterator);
3920 while (formatter.hasMoreLines())
3922 out << formatter.nextLine();
3923 if (formatter.hasMoreLines())
3924 out << streamIterator.getOutputEOL();
3927 // this can happen if the file if missing a closing brace and break-blocks is requested
3928 if (formatter.getIsLineReady())
3930 out << streamIterator.getOutputEOL();
3931 out << formatter.nextLine();
3936 size_t textSizeOut = out.str().length();
3937 char* pTextOut = fpMemoryAlloc((long)textSizeOut + 1); // call memory allocation function
3938 if (pTextOut == nullptr)
3940 fpErrorHandler(120, "Allocation failure on output.");
3944 strcpy(pTextOut, out.str().c_str());
3946 // The checksum is an assert in the console build and ASFormatter.
3947 // This error returns the incorrectly formatted file to the editor.
3948 // This is done to allow the file to be saved for debugging purposes.
3949 if (formatter.getChecksumDiff() != 0)
3952 "The incorrectly formatted file will be returned for debugging.");
3957 extern "C" EXPORT const char* STDCALL AStyleGetVersion(void)
3962 // ASTYLECON_LIB is defined to exclude "main" from the test programs
3963 #elif !defined(ASTYLECON_LIB)
3965 //----------------------------------------------------------------------------
3966 // main function for ASConsole build
3967 //----------------------------------------------------------------------------
3969 int main(int argc, char** argv)
3972 ASFormatter formatter;
3973 auto console = make_shared<ASConsole>(formatter);
3975 // process command line and options file
3976 // build the vectors fileNameVector, optionsVector, and fileOptionsVector
3977 vector<string> argvOptions;
3978 argvOptions = console->getArgvOptions(argc, argv);
3979 console->processOptions(argvOptions);
3981 // if no files have been given, use cin for input and cout for output
3982 if (!console->fileNameVectorIsEmpty())
3983 console->processFiles();
3985 console->formatCinToCout();
3987 return EXIT_SUCCESS;
3990 #endif // ASTYLE_LIB