openjp2/j2k: Report error if all wanted components are not decoded.
[openjpeg.git] / thirdparty / astyle / astyle_main.cpp
1 // astyle_main.cpp
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.
5
6 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7  *   AStyle_main source file map.
8  *   This source file contains several classes.
9  *   They are arranged as follows.
10  *   ---------------------------------------
11  *   namespace astyle {
12  *   ASStreamIterator methods
13  *   ASConsole methods
14  *      // Windows specific
15  *      // Linux specific
16  *   ASLibrary methods
17  *      // Windows specific
18  *      // Linux specific
19  *   ASOptions methods
20  *   ASEncoding 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
27  *      main entry point
28  *  ---------------------------------------
29  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
30  */
31
32 //-----------------------------------------------------------------------------
33 // headers
34 //-----------------------------------------------------------------------------
35
36 #include "astyle_main.h"
37
38 #include <algorithm>
39 #include <cerrno>
40 #include <clocale>              // needed by some compilers
41 #include <cstdlib>
42 #include <fstream>
43 #include <sstream>
44
45 // includes for recursive getFileNames() function
46 #ifdef _WIN32
47         #undef UNICODE          // use ASCII windows functions
48         #include <windows.h>
49 #else
50         #include <dirent.h>
51         #include <unistd.h>
52         #include <sys/stat.h>
53         #ifdef __VMS
54                 #include <unixlib.h>
55                 #include <rms.h>
56                 #include <ssdef.h>
57                 #include <stsdef.h>
58                 #include <lib$routines.h>
59                 #include <starlet.h>
60         #endif /* __VMS */
61 #endif
62
63 //-----------------------------------------------------------------------------
64 // declarations
65 //-----------------------------------------------------------------------------
66
67 // turn off MinGW automatic file globbing
68 // this CANNOT be in the astyle namespace
69 #ifndef ASTYLE_LIB
70         int _CRT_glob = 0;
71 #endif
72
73 //----------------------------------------------------------------------------
74 // astyle namespace
75 //----------------------------------------------------------------------------
76
77 namespace astyle {
78 //
79 // console build variables
80 #ifndef ASTYLE_LIB
81         #ifdef _WIN32
82                 char g_fileSeparator = '\\';     // Windows file separator
83                 bool g_isCaseSensitive = false;  // Windows IS NOT case sensitive
84         #else
85                 char g_fileSeparator = '/';      // Linux file separator
86                 bool g_isCaseSensitive = true;   // Linux IS case sensitive
87         #endif  // _WIN32
88 #endif  // ASTYLE_LIB
89
90 // java library build variables
91 #ifdef ASTYLE_JNI
92         JNIEnv*   g_env;
93         jobject   g_obj;
94         jmethodID g_mid;
95 #endif
96
97 const char* g_version = "3.0";
98
99 //-----------------------------------------------------------------------------
100 // ASStreamIterator class
101 // typename will be istringstream for GUI and istream otherwise
102 //-----------------------------------------------------------------------------
103
104 template<typename T>
105 ASStreamIterator<T>::ASStreamIterator(T* in)
106 {
107         inStream = in;
108         buffer.reserve(200);
109         eolWindows = 0;
110         eolLinux = 0;
111         eolMacOld = 0;
112         peekStart = 0;
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);
119 }
120
121 template<typename T>
122 ASStreamIterator<T>::~ASStreamIterator()
123 {
124 }
125
126 /**
127 * get the length of the input stream.
128 * streamLength variable is set by the constructor.
129 *
130 * @return     length of the input file stream, converted to an int.
131 */
132 template<typename T>
133 int ASStreamIterator<T>::getStreamLength() const
134 {
135         return static_cast<int>(streamLength);
136 }
137
138 /**
139  * read the input stream, delete any end of line characters,
140  *     and build a string that contains the input line.
141  *
142  * @return        string containing the next input line minus any end of line characters
143  */
144 template<typename T>
145 string ASStreamIterator<T>::nextLine(bool emptyLineWasDeleted)
146 {
147         // verify that the current position is correct
148         assert(peekStart == 0);
149
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
152         if (prevLineDeleted)
153         {
154                 prevLineDeleted = false;
155                 checkForEmptyLine = true;
156         }
157         if (!emptyLineWasDeleted)
158                 prevBuffer = buffer;
159         else
160                 prevLineDeleted = true;
161
162         // read the next record
163         buffer.clear();
164         char ch;
165         inStream->get(ch);
166
167         while (!inStream->eof() && ch != '\n' && ch != '\r')
168         {
169                 buffer.append(1, ch);
170                 inStream->get(ch);
171         }
172
173         if (inStream->eof())
174         {
175                 return buffer;
176         }
177
178         int peekCh = inStream->peek();
179
180         // find input end-of-line characters
181         if (!inStream->eof())
182         {
183                 if (ch == '\r')         // CR+LF is windows otherwise Mac OS 9
184                 {
185                         if (peekCh == '\n')
186                         {
187                                 inStream->get();
188                                 eolWindows++;
189                         }
190                         else
191                                 eolMacOld++;
192                 }
193                 else                    // LF is Linux, allow for improbable LF/CR
194                 {
195                         if (peekCh == '\r')
196                         {
197                                 inStream->get();
198                                 eolWindows++;
199                         }
200                         else
201                                 eolLinux++;
202                 }
203         }
204         else
205         {
206                 inStream->clear();
207         }
208
209         // set output end of line characters
210         if (eolWindows >= eolLinux)
211         {
212                 if (eolWindows >= eolMacOld)
213                         outputEOL = "\r\n";     // Windows (CR+LF)
214                 else
215                         outputEOL = "\r";       // MacOld (CR)
216         }
217         else if (eolLinux >= eolMacOld)
218                 outputEOL = "\n";           // Linux (LF)
219         else
220                 outputEOL = "\r";           // MacOld (CR)
221
222         return buffer;
223 }
224
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
229 template<typename T>
230 string ASStreamIterator<T>::peekNextLine()
231 {
232         assert(hasMoreLines());
233         string nextLine_;
234         char ch;
235
236         if (peekStart == 0)
237                 peekStart = inStream->tellg();
238
239         // read the next record
240         inStream->get(ch);
241         while (!inStream->eof() && ch != '\n' && ch != '\r')
242         {
243                 nextLine_.append(1, ch);
244                 inStream->get(ch);
245         }
246
247         if (inStream->eof())
248         {
249                 return nextLine_;
250         }
251
252         int peekCh = inStream->peek();
253
254         // remove end-of-line characters
255         if (!inStream->eof())
256         {
257                 if ((peekCh == '\n' || peekCh == '\r') && peekCh != ch)
258                         inStream->get();
259         }
260
261         return nextLine_;
262 }
263
264 // reset current position and EOF for peekNextLine()
265 template<typename T>
266 void ASStreamIterator<T>::peekReset()
267 {
268         assert(peekStart != 0);
269         inStream->clear();
270         inStream->seekg(peekStart);
271         peekStart = 0;
272 }
273
274 // save the last input line after input has reached EOF
275 template<typename T>
276 void ASStreamIterator<T>::saveLastInputLine()
277 {
278         assert(inStream->eof());
279         prevBuffer = buffer;
280 }
281
282 // return position of the get pointer
283 template<typename T>
284 streamoff ASStreamIterator<T>::tellg()
285 {
286         return inStream->tellg();
287 }
288
289 // check for a change in line ends
290 template<typename T>
291 bool ASStreamIterator<T>::getLineEndChange(int lineEndFormat) const
292 {
293         assert(lineEndFormat == LINEEND_DEFAULT
294                || lineEndFormat == LINEEND_WINDOWS
295                || lineEndFormat == LINEEND_LINUX
296                || lineEndFormat == LINEEND_MACOLD);
297
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);
305         else
306         {
307                 if (eolWindows > 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);
313         }
314         return lineEndChange;
315 }
316
317 //-----------------------------------------------------------------------------
318 // ASConsole class
319 // main function will be included only in the console build
320 //-----------------------------------------------------------------------------
321
322 #ifndef ASTYLE_LIB
323
324 ASConsole::ASConsole(ASFormatter& formatterArg) : formatter(formatterArg)
325 {
326         errorStream = &cerr;
327         // command line options
328         isRecursive = false;
329         isDryRun = false;
330         noBackup = false;
331         preserveDate = false;
332         isVerbose = false;
333         isQuiet = false;
334         isFormattedOnly = false;
335         ignoreExcludeErrors = false;
336         ignoreExcludeErrorsDisplay = false;
337         optionsFileRequired = false;
338         useAscii = false;
339         // other variables
340         bypassBrowserOpen = false;
341         hasWildcard = false;
342         filesAreIdentical = true;
343         lineEndsMixed = false;
344         origSuffix = ".orig";
345         mainDirectoryLength = 0;
346         filesFormatted = 0;
347         filesUnchanged = 0;
348         linesOut = 0;
349 }
350
351 ASConsole::~ASConsole()
352 {}
353
354 // rewrite a stringstream converting the line ends
355 void ASConsole::convertLineEnds(ostringstream& out, int lineEnd)
356 {
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++)
362         {
363                 if (inStr[pos] == '\r')
364                 {
365                         if (inStr[pos + 1] == '\n')
366                         {
367                                 // CRLF
368                                 if (lineEnd == LINEEND_CR)
369                                 {
370                                         outStr += inStr[pos];           // Delete the LF
371                                         pos++;
372                                         continue;
373                                 }
374                                 else if (lineEnd == LINEEND_LF)
375                                 {
376                                         outStr += inStr[pos + 1];               // Delete the CR
377                                         pos++;
378                                         continue;
379                                 }
380                                 else
381                                 {
382                                         outStr += inStr[pos];           // Do not change
383                                         outStr += inStr[pos + 1];
384                                         pos++;
385                                         continue;
386                                 }
387                         }
388                         else
389                         {
390                                 // CR
391                                 if (lineEnd == LINEEND_CRLF)
392                                 {
393                                         outStr += inStr[pos];           // Insert the CR
394                                         outStr += '\n';                         // Insert the LF
395                                         continue;
396                                 }
397                                 else if (lineEnd == LINEEND_LF)
398                                 {
399                                         outStr += '\n';                         // Insert the LF
400                                         continue;
401                                 }
402                                 else
403                                 {
404                                         outStr += inStr[pos];           // Do not change
405                                         continue;
406                                 }
407                         }
408                 }
409                 else if (inStr[pos] == '\n')
410                 {
411                         // LF
412                         if (lineEnd == LINEEND_CRLF)
413                         {
414                                 outStr += '\r';                         // Insert the CR
415                                 outStr += inStr[pos];           // Insert the LF
416                                 continue;
417                         }
418                         else if (lineEnd == LINEEND_CR)
419                         {
420                                 outStr += '\r';                         // Insert the CR
421                                 continue;
422                         }
423                         else
424                         {
425                                 outStr += inStr[pos];           // Do not change
426                                 continue;
427                         }
428                 }
429                 else
430                 {
431                         outStr += inStr[pos];           // Write the current char
432                 }
433         }
434         // replace the stream
435         out.str(outStr);
436 }
437
438 void ASConsole::correctMixedLineEnds(ostringstream& out)
439 {
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);
448 }
449
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
454 {
455         FileEncoding encoding = ENCODING_8BIT;
456
457         if (dataSize >= 4 && memcmp(data, "\x00\x00\xFE\xFF", 4) == 0)
458                 encoding = UTF_32BE;
459         else if (dataSize >= 4 && memcmp(data, "\xFF\xFE\x00\x00", 4) == 0)
460                 encoding = UTF_32LE;
461         else if (dataSize >= 2 && memcmp(data, "\xFE\xFF", 2) == 0)
462                 encoding = UTF_16BE;
463         else if (dataSize >= 2 && memcmp(data, "\xFF\xFE", 2) == 0)
464                 encoding = UTF_16LE;
465
466         return encoding;
467 }
468
469 // error exit without a message
470 void ASConsole::error() const
471 {
472         (*errorStream) << _("\nArtistic Style has terminated") << endl;
473         exit(EXIT_FAILURE);
474 }
475
476 // error exit with a message
477 void ASConsole::error(const char* why, const char* what) const
478 {
479         (*errorStream) << why << ' ' << what << endl;
480         error();
481 }
482
483 /**
484  * If no files have been given, use cin for input and cout for output.
485  *
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.
488  */
489 void ASConsole::formatCinToCout()
490 {
491         // check for files from --stdin= and --stdout=
492         if (!stdPathIn.empty())
493         {
494                 if (!freopen(stdPathIn.c_str(), "r", stdin))
495                         error("Cannot open input file", stdPathIn.c_str());
496         }
497         if (!stdPathOut.empty())
498         {
499                 if (!freopen(stdPathOut.c_str(), "w", stdout))
500                         error("Cannot open output file", stdPathOut.c_str());
501
502         }
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;
511         char ch;
512         inStream->get(ch);
513         while (!inStream->eof() && !inStream->fail())
514         {
515                 outStream.put(ch);
516                 inStream->get(ch);
517         }
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.
521 #ifdef _WIN32
522         LineEndFormat lineEndFormat = LINEEND_DEFAULT;
523 #else
524         LineEndFormat lineEndFormat = formatter.getLineEndFormat();
525 #endif // _WIN32
526         initializeOutputEOL(lineEndFormat);
527         formatter.init(&streamIterator);
528
529         while (formatter.hasMoreLines())
530         {
531                 cout << formatter.nextLine();
532                 if (formatter.hasMoreLines())
533                 {
534                         setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
535                         cout << outputEOL;
536                 }
537                 else
538                 {
539                         // this can happen if the file if missing a closing brace and break-blocks is requested
540                         if (formatter.getIsLineReady())
541                         {
542                                 setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
543                                 cout << outputEOL;
544                                 cout << formatter.nextLine();
545                         }
546                 }
547         }
548         cout.flush();
549 }
550
551 /**
552  * Open input file, format it, and close the output.
553  *
554  * @param fileName_     The path and name of the file to be processed.
555  */
556 void ASConsole::formatFile(const string& fileName_)
557 {
558         stringstream in;
559         ostringstream out;
560         FileEncoding encoding = readFile(fileName_, in);
561
562         // Unless a specific language mode has been set, set the language mode
563         // according to the file's suffix.
564         if (!formatter.getModeManuallySet())
565         {
566                 if (stringEndsWith(fileName_, string(".java")))
567                         formatter.setJavaStyle();
568                 else if (stringEndsWith(fileName_, string(".cs")))
569                         formatter.setSharpStyle();
570                 else
571                         formatter.setCStyle();
572         }
573
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);
582
583         // format the file
584         while (formatter.hasMoreLines())
585         {
586                 nextLine = formatter.nextLine();
587                 out << nextLine;
588                 linesOut++;
589                 if (formatter.hasMoreLines())
590                 {
591                         setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
592                         out << outputEOL;
593                 }
594                 else
595                 {
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())
599                         {
600                                 setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
601                                 out << outputEOL;
602                                 nextLine = formatter.nextLine();
603                                 out << nextLine;
604                                 linesOut++;
605                                 streamIterator.saveLastInputLine();
606                         }
607                 }
608
609                 if (filesAreIdentical)
610                 {
611                         if (streamIterator.checkForEmptyLine)
612                         {
613                                 if (nextLine.find_first_not_of(" \t") != string::npos)
614                                         filesAreIdentical = false;
615                         }
616                         else if (!streamIterator.compareToInputBuffer(nextLine))
617                                 filesAreIdentical = false;
618                         streamIterator.checkForEmptyLine = false;
619                 }
620         }
621         // correct for mixed line ends
622         if (lineEndsMixed)
623         {
624                 correctMixedLineEnds(out);
625                 filesAreIdentical = false;
626         }
627
628         // remove targetDirectory from filename if required by print
629         string displayName;
630         if (hasWildcard)
631                 displayName = fileName_.substr(targetDirectory.length() + 1);
632         else
633                 displayName = fileName_;
634
635         // if file has changed, write the new file
636         if (!filesAreIdentical || streamIterator.getLineEndChange(lineEndFormat))
637         {
638                 if (!isDryRun)
639                         writeFile(fileName_, encoding, out);
640                 printMsg(_("Formatted  %s\n"), displayName);
641                 filesFormatted++;
642         }
643         else
644         {
645                 if (!isFormattedOnly)
646                         printMsg(_("Unchanged  %s\n"), displayName);
647                 filesUnchanged++;
648         }
649
650         assert(formatter.getChecksumDiff() == 0);
651 }
652
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
656 {
657         vector<string> argvOptions;
658         for (int i = 1; i < argc; i++)
659         {
660                 argvOptions.emplace_back(string(argv[i]));
661         }
662         return argvOptions;
663 }
664
665 // for unit testing
666 vector<bool> ASConsole::getExcludeHitsVector() const
667 { return excludeHitsVector; }
668
669 // for unit testing
670 vector<string> ASConsole::getExcludeVector() const
671 { return excludeVector; }
672
673 // for unit testing
674 vector<string> ASConsole::getFileName() const
675 { return fileName; }
676
677 // for unit testing
678 vector<string> ASConsole::getFileNameVector() const
679 { return fileNameVector; }
680
681 // for unit testing
682 vector<string> ASConsole::getFileOptionsVector() const
683 { return fileOptionsVector; }
684
685 // for unit testing
686 bool ASConsole::getFilesAreIdentical() const
687 { return filesAreIdentical; }
688
689 // for unit testing
690 int ASConsole::getFilesFormatted() const
691 { return filesFormatted; }
692
693 // for unit testing
694 bool ASConsole::getIgnoreExcludeErrors() const
695 { return ignoreExcludeErrors; }
696
697 // for unit testing
698 bool ASConsole::getIgnoreExcludeErrorsDisplay() const
699 { return ignoreExcludeErrorsDisplay; }
700
701 // for unit testing
702 bool ASConsole::getIsDryRun() const
703 { return isDryRun; }
704
705 // for unit testing
706 bool ASConsole::getIsFormattedOnly() const
707 { return isFormattedOnly; }
708
709 // for unit testing
710 string ASConsole::getLanguageID() const
711 { return localizer.getLanguageID(); }
712
713 // for unit testing
714 bool ASConsole::getIsQuiet() const
715 { return isQuiet; }
716
717 // for unit testing
718 bool ASConsole::getIsRecursive() const
719 { return isRecursive; }
720
721 // for unit testing
722 bool ASConsole::getIsVerbose() const
723 { return isVerbose; }
724
725 // for unit testing
726 bool ASConsole::getLineEndsMixed() const
727 { return lineEndsMixed; }
728
729 // for unit testing
730 bool ASConsole::getNoBackup() const
731 { return noBackup; }
732
733 // for unit testing
734 string ASConsole::getOptionsFileName() const
735 { return optionsFileName; }
736
737 // for unit testing
738 vector<string> ASConsole::getOptionsVector() const
739 { return optionsVector; }
740
741 // for unit testing
742 string ASConsole::getOrigSuffix() const
743 { return origSuffix; }
744
745 // for unit testing
746 bool ASConsole::getPreserveDate() const
747 { return preserveDate; }
748
749 // for unit testing
750 string ASConsole::getStdPathIn() const
751 { return stdPathIn; }
752
753 // for unit testing
754 string ASConsole::getStdPathOut() const
755 { return stdPathOut; }
756
757 // for unit testing
758 void ASConsole::setBypassBrowserOpen(bool state)
759 { bypassBrowserOpen = state; }
760
761 // for unit testing
762 ostream* ASConsole::getErrorStream() const
763 {
764         return errorStream;
765 }
766
767 void ASConsole::setErrorStream(ostream* errStreamPtr)
768 {
769         errorStream = errStreamPtr;
770 }
771
772 string ASConsole::getParam(const string& arg, const char* op)
773 {
774         return arg.substr(strlen(op));
775 }
776
777 // initialize output end of line
778 void ASConsole::initializeOutputEOL(LineEndFormat lineEndFormat)
779 {
780         assert(lineEndFormat == LINEEND_DEFAULT
781                || lineEndFormat == LINEEND_WINDOWS
782                || lineEndFormat == LINEEND_LINUX
783                || lineEndFormat == LINEEND_MACOLD);
784
785         outputEOL.clear();                      // current line end
786         prevEOL.clear();                        // previous line end
787         lineEndsMixed = false;          // output has mixed line ends, LINEEND_DEFAULT only
788
789         if (lineEndFormat == LINEEND_WINDOWS)
790                 outputEOL = "\r\n";
791         else if (lineEndFormat == LINEEND_LINUX)
792                 outputEOL = "\n";
793         else if (lineEndFormat == LINEEND_MACOLD)
794                 outputEOL = "\r";
795         else
796                 outputEOL.clear();
797 }
798
799 FileEncoding ASConsole::readFile(const string& fileName_, stringstream& in) const
800 {
801         const int blockSize = 65536;    // 64 KB
802         ifstream fin(fileName_.c_str(), ios::binary);
803         if (!fin)
804                 error("Cannot open input file", fileName_.c_str());
805         char* data = new (nothrow) char[blockSize];
806         if (data == nullptr)
807                 error("Cannot allocate memory for input file", fileName_.c_str());
808         fin.read(data, blockSize);
809         if (fin.bad())
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)
818         {
819                 if (encoding == UTF_16LE || encoding == UTF_16BE)
820                 {
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);
829                         delete[] utf8Out;
830                 }
831                 else
832                         in << string(data, dataSize);
833                 fin.read(data, blockSize);
834                 if (fin.bad())
835                         error("Cannot read input file", fileName_.c_str());
836                 dataSize = static_cast<size_t>(fin.gcount());
837                 firstBlock = false;
838         }
839         fin.close();
840         delete[] data;
841         return encoding;
842 }
843
844 void ASConsole::setIgnoreExcludeErrors(bool state)
845 { ignoreExcludeErrors = state; }
846
847 void ASConsole::setIgnoreExcludeErrorsAndDisplay(bool state)
848 { ignoreExcludeErrors = state; ignoreExcludeErrorsDisplay = state; }
849
850 void ASConsole::setIsFormattedOnly(bool state)
851 { isFormattedOnly = state; }
852
853 void ASConsole::setIsQuiet(bool state)
854 { isQuiet = state; }
855
856 void ASConsole::setIsRecursive(bool state)
857 { isRecursive = state; }
858
859 void ASConsole::setIsDryRun(bool state)
860 { isDryRun = state; }
861
862 void ASConsole::setIsVerbose(bool state)
863 { isVerbose = state; }
864
865 void ASConsole::setNoBackup(bool state)
866 { noBackup = state; }
867
868 void ASConsole::setOptionsFileName(const string& name)
869 { optionsFileName = name; }
870
871 void ASConsole::setOrigSuffix(const string& suffix)
872 { origSuffix = suffix; }
873
874 void ASConsole::setPreserveDate(bool state)
875 { preserveDate = state; }
876
877 void ASConsole::setStdPathIn(const string& path)
878 { stdPathIn = path; }
879
880 void ASConsole::setStdPathOut(const string& path)
881 { stdPathOut = path; }
882
883 // set outputEOL variable
884 void ASConsole::setOutputEOL(LineEndFormat lineEndFormat, const string& currentEOL)
885 {
886         if (lineEndFormat == LINEEND_DEFAULT)
887         {
888                 outputEOL = currentEOL;
889                 if (prevEOL.empty())
890                         prevEOL = outputEOL;
891                 if (prevEOL != outputEOL)
892                 {
893                         lineEndsMixed = true;
894                         filesAreIdentical = false;
895                         prevEOL = outputEOL;
896                 }
897         }
898         else
899         {
900                 prevEOL = currentEOL;
901                 if (prevEOL != outputEOL)
902                         filesAreIdentical = false;
903         }
904 }
905
906 #ifdef _WIN32  // Windows specific
907
908 /**
909  * WINDOWS function to display the last system error.
910  */
911 void ASConsole::displayLastError()
912 {
913         LPSTR msgBuf;
914         DWORD lastError = GetLastError();
915         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
916                       nullptr,
917                       lastError,
918                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  // Default language
919                       (LPSTR) &msgBuf,
920                       0,
921                       nullptr
922                      );
923         // Display the string.
924         (*errorStream) << "Error (" << lastError << ") " << msgBuf << endl;
925         // Free the buffer.
926         LocalFree(msgBuf);
927 }
928
929 /**
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.
933  *
934  * @return              The path of the current directory
935  */
936 string ASConsole::getCurrentDirectory(const string& fileName_) const
937 {
938         char currdir[MAX_PATH];
939         currdir[0] = '\0';
940         if (!GetCurrentDirectory(sizeof(currdir), currdir))
941                 error("Cannot find file", fileName_.c_str());
942         return string(currdir);
943 }
944
945 /**
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.
948  *
949  * @param directory     The path of the directory to be processed.
950  * @param wildcard      The wildcard to be processed (e.g. *.cpp).
951  */
952 void ASConsole::getFileNames(const string& directory, const string& wildcard)
953 {
954         vector<string> subDirectory;    // sub directories of directory
955         WIN32_FIND_DATA findFileData;   // for FindFirstFile and FindNextFile
956
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);
961
962         if (hFind == INVALID_HANDLE_VALUE)
963         {
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
967                 displayLastError();
968                 error(_("Cannot open directory"), directory.c_str());
969         }
970
971         // save files and sub directories
972         do
973         {
974                 // skip hidden or read only
975                 if (findFileData.cFileName[0] == '.'
976                         || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
977                         || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
978                         continue;
979
980                 // is this a sub directory
981                 if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
982                 {
983                         if (!isRecursive)
984                                 continue;
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));
989                         else
990                                 subDirectory.emplace_back(subDirectoryPath);
991                         continue;
992                 }
993
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))
1000                 {
1001                         if (isExcluded)
1002                                 printMsg(_("Exclude  %s\n"), filePathName.substr(mainDirectoryLength));
1003                         else
1004                                 fileName.emplace_back(filePathName);
1005                 }
1006         }
1007         while (FindNextFile(hFind, &findFileData) != 0);
1008
1009         // check for processing error
1010         ::FindClose(hFind);
1011         DWORD dwError = GetLastError();
1012         if (dwError != ERROR_NO_MORE_FILES)
1013                 error("Error processing directory", directory.c_str());
1014
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);
1019
1020         return;
1021 }
1022
1023 /**
1024  * WINDOWS function to format a number according to the current locale.
1025  * This formats positive integers only, no float.
1026  *
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.
1030  */
1031 string ASConsole::getNumberFormat(int num, size_t lcid) const
1032 {
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");
1039 #endif
1040         // convert num to a string
1041         stringstream alphaNum;
1042         alphaNum << num;
1043         string number = alphaNum.str();
1044         if (useAscii)
1045                 return number;
1046
1047         // format the number using the Windows API
1048         if (lcid == 0)
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)
1053                 return number;
1054         ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, outBuf, outSize);
1055         string formattedNum(outBuf);
1056         delete[] 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)
1061                 return number;
1062         ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, decBuf, decSize);
1063         size_t i = formattedNum.rfind(decBuf);
1064         delete[] decBuf;
1065         if (i != string::npos)
1066                 formattedNum.erase(i);
1067         if (!formattedNum.length())
1068                 formattedNum = "0";
1069         return formattedNum;
1070 }
1071
1072 /**
1073  * WINDOWS function to open a HTML file in the default browser.
1074  */
1075 void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
1076 {
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++)
1082         {
1083                 const char* envPath = getenv(envPaths[i]);
1084                 if (envPath == nullptr)
1085                         continue;
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)
1092                         break;
1093         }
1094         htmlDefaultPath.append("\\");
1095
1096         // build file path
1097         string htmlFilePath;
1098         if (filePathIn == nullptr)
1099                 htmlFilePath = htmlDefaultPath + "astyle.html";
1100         else
1101         {
1102                 if (strpbrk(filePathIn, "\\/") == nullptr)
1103                         htmlFilePath = htmlDefaultPath + filePathIn;
1104                 else
1105                         htmlFilePath = filePathIn;
1106         }
1107         standardizePath(htmlFilePath);
1108         if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
1109         {
1110                 printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
1111                 return;
1112         }
1113
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;
1119
1120         // browser open will be bypassed in test programs
1121         printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
1122         if (!bypassBrowserOpen)
1123         {
1124                 int ret = ShellExecuteEx(&sei);
1125                 if (!ret)
1126                         error(_("Command execute failure"), htmlFilePath.c_str());
1127         }
1128 }
1129
1130 #else  // Linux specific
1131
1132 /**
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.
1136  *
1137  * @param fileName_     The filename is used only for  the error message.
1138  * @return              The path of the current directory
1139  */
1140 string ASConsole::getCurrentDirectory(const string& fileName_) const
1141 {
1142         char* currdir = getenv("PWD");
1143         if (currdir == nullptr)
1144                 error("Cannot find file", fileName_.c_str());
1145         return string(currdir);
1146 }
1147
1148 /**
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.
1151  *
1152  * @param directory     The path of the directory to be processed.
1153  * @param wildcard      The wildcard to be processed (e.g. *.cpp).
1154  */
1155 void ASConsole::getFileNames(const string& directory, const string& wildcard)
1156 {
1157         struct dirent* entry;           // entry from readdir()
1158         struct stat statbuf;            // entry from stat()
1159         vector<string> subDirectory;    // sub directories of this directory
1160
1161         // errno is defined in <errno.h> and is set for errors in opendir, readdir, or stat
1162         errno = 0;
1163
1164         DIR* dp = opendir(directory.c_str());
1165         if (dp == nullptr)
1166                 error(_("Cannot open directory"), directory.c_str());
1167
1168         // save the first fileName entry for this recursion
1169         const unsigned firstEntry = fileName.size();
1170
1171         // save files and sub directories
1172         while ((entry = readdir(dp)) != nullptr)
1173         {
1174                 // get file status
1175                 string entryFilepath = directory + g_fileSeparator + entry->d_name;
1176                 if (stat(entryFilepath.c_str(), &statbuf) != 0)
1177                 {
1178                         if (errno == EOVERFLOW)         // file over 2 GB is OK
1179                         {
1180                                 errno = 0;
1181                                 continue;
1182                         }
1183                         perror("errno message");
1184                         error("Error getting file status in directory", directory.c_str());
1185                 }
1186                 // skip hidden or read only
1187                 if (entry->d_name[0] == '.' || !(statbuf.st_mode & S_IWUSR))
1188                         continue;
1189                 // if a sub directory and recursive, save sub directory
1190                 if (S_ISDIR(statbuf.st_mode) && isRecursive)
1191                 {
1192                         if (isPathExclued(entryFilepath))
1193                                 printMsg(_("Exclude  %s\n"), entryFilepath.substr(mainDirectoryLength));
1194                         else
1195                                 subDirectory.emplace_back(entryFilepath);
1196                         continue;
1197                 }
1198
1199                 // if a file, save file name
1200                 if (S_ISREG(statbuf.st_mode))
1201                 {
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)
1206                         {
1207                                 if (isExcluded)
1208                                         printMsg(_("Exclude  %s\n"), entryFilepath.substr(mainDirectoryLength));
1209                                 else
1210                                         fileName.emplace_back(entryFilepath);
1211                         }
1212                 }
1213         }
1214
1215         if (closedir(dp) != 0)
1216         {
1217                 perror("errno message");
1218                 error("Error reading directory", directory.c_str());
1219         }
1220
1221         // sort the current entries for fileName
1222         if (firstEntry < fileName.size())
1223                 sort(&fileName[firstEntry], &fileName[fileName.size()]);
1224
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++)
1230         {
1231                 getFileNames(subDirectory[i], wildcard);
1232         }
1233 }
1234
1235 /**
1236  * LINUX function to get locale information and call getNumberFormat.
1237  * This formats positive integers only, no float.
1238  *
1239  * @param num           The number to be formatted.
1240  *                  size_t is for compatibility with the Windows function.
1241  * @return                      The formatted number.
1242  */
1243 string ASConsole::getNumberFormat(int num, size_t /*lcid*/) const
1244 {
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");
1251 #endif
1252
1253         // get the locale info
1254         struct lconv* lc;
1255         lc = localeconv();
1256
1257         // format the number
1258         return getNumberFormat(num, lc->grouping, lc->thousands_sep);
1259 }
1260
1261 /**
1262  * LINUX function to format a number according to the current locale.
1263  * This formats positive integers only, no float.
1264  *
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.
1269  */
1270 string ASConsole::getNumberFormat(int num, const char* groupingArg, const char* separator) const
1271 {
1272         // convert num to a string
1273         stringstream alphaNum;
1274         alphaNum << num;
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
1282         if (grouping == 0)
1283                 grouping = number.length();
1284         while (i > 0)
1285         {
1286                 // extract a group of numbers
1287                 string group;
1288                 if (i < grouping)
1289                         group = number;
1290                 else
1291                         group = number.substr(i - grouping);
1292                 // update formatted number
1293                 formattedNum.insert(0, group);
1294                 i -= grouping;
1295                 if (i < 0)
1296                         i = 0;
1297                 if (i > 0)
1298                         formattedNum.insert(0, separator);
1299                 number.erase(i);
1300                 // update grouping
1301                 if (groupingArg[ig] != '\0'
1302                         && groupingArg[ig + 1] != '\0')
1303                         grouping = groupingArg[++ig];
1304         }
1305         return formattedNum;
1306 }
1307
1308 /**
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.
1313  */
1314 void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
1315 {
1316         struct stat statbuf;
1317         string htmlDefaultPath = "/usr/share/doc/astyle/html/";
1318         string htmlDefaultFile = "astyle.html";
1319
1320         // build file path
1321         string htmlFilePath;
1322         if (filePathIn == nullptr)
1323                 htmlFilePath = htmlDefaultPath + htmlDefaultFile;
1324         else
1325         {
1326                 if (strpbrk(filePathIn, "\\/") == nullptr)
1327                         htmlFilePath = htmlDefaultPath + filePathIn;
1328                 else
1329                         htmlFilePath = filePathIn;
1330         }
1331         standardizePath(htmlFilePath);
1332         if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
1333         {
1334                 printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
1335                 return;
1336         }
1337
1338         // get search paths
1339         const char* envPaths = getenv("PATH");
1340         if (envPaths == nullptr)
1341                 envPaths = "?";
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
1347 #ifdef __APPLE__
1348         const char* fileOpen = "open";
1349 #else
1350         const char* fileOpen = "xdg-open";
1351 #endif
1352         string searchPath;
1353         char* searchDir = strtok(paths, ":");
1354         while (searchDir != nullptr)
1355         {
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))
1362                         break;
1363                 searchDir = strtok(nullptr, ":");
1364         }
1365         delete[] paths;
1366         if (searchDir == nullptr)
1367                 error(_("Command is not installed"), fileOpen);
1368
1369         // browser open will be bypassed in test programs
1370         printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
1371         if (!bypassBrowserOpen)
1372         {
1373                 execlp(fileOpen, fileOpen, htmlFilePath.c_str(), nullptr);
1374                 // execlp will NOT return if successful
1375                 error(_("Command execute failure"), fileOpen);
1376         }
1377 }
1378
1379 #endif  // _WIN32
1380
1381 // get individual file names from the command-line file path
1382 void ASConsole::getFilePaths(const string& filePath)
1383 {
1384         fileName.clear();
1385         targetDirectory = string();
1386         targetFilename = string();
1387
1388         // separate directory and file name
1389         size_t separator = filePath.find_last_of(g_fileSeparator);
1390         if (separator == string::npos)
1391         {
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
1396         }
1397         else
1398         {
1399                 targetDirectory = filePath.substr(0, separator);
1400                 targetFilename  = filePath.substr(separator + 1);
1401                 mainDirectoryLength = targetDirectory.length() + 1;    // +1 includes trailing separator
1402         }
1403
1404         if (targetFilename.length() == 0)
1405         {
1406                 fprintf(stderr, _("Missing filename in %s\n"), filePath.c_str());
1407                 error();
1408         }
1409
1410         // check filename for wildcards
1411         hasWildcard = false;
1412         if (targetFilename.find_first_of("*?") != string::npos)
1413                 hasWildcard = true;
1414
1415         // clear exclude hits vector
1416         size_t excludeHitsVectorSize = excludeHitsVector.size();
1417         for (size_t ix = 0; ix < excludeHitsVectorSize; ix++)
1418                 excludeHitsVector[ix] = false;
1419
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)
1423         {
1424                 fprintf(stderr, "%s\n", _("Recursive option with no wildcard"));
1425 #ifndef _WIN32
1426                 fprintf(stderr, "%s\n", _("Did you intend quote the filename"));
1427 #endif
1428                 error();
1429         }
1430
1431         // display directory name for wildcard processing
1432         if (hasWildcard)
1433         {
1434                 printSeparatingLine();
1435                 printMsg(_("Directory  %s\n"), targetDirectory + g_fileSeparator + targetFilename);
1436         }
1437
1438         // create a vector of paths and file names to process
1439         if (hasWildcard || isRecursive)
1440                 getFileNames(targetDirectory, targetFilename);
1441         else
1442         {
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);
1448         }
1449
1450         // check for unprocessed excludes
1451         bool excludeErr = false;
1452         for (size_t ix = 0; ix < excludeHitsVector.size(); ix++)
1453         {
1454                 if (!excludeHitsVector[ix])
1455                 {
1456                         excludeErr = true;
1457                         if (!ignoreExcludeErrorsDisplay)
1458                         {
1459                                 if (ignoreExcludeErrors)
1460                                         printMsg(_("Exclude (unmatched)  %s\n"), excludeVector[ix]);
1461                                 else
1462                                         fprintf(stderr, _("Exclude (unmatched)  %s\n"), excludeVector[ix].c_str());
1463                         }
1464                         else
1465                         {
1466                                 if (!ignoreExcludeErrors)
1467                                         fprintf(stderr, _("Exclude (unmatched)  %s\n"), excludeVector[ix].c_str());
1468                         }
1469                 }
1470         }
1471
1472         if (excludeErr && !ignoreExcludeErrors)
1473         {
1474                 if (hasWildcard && !isRecursive)
1475                         fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
1476                 error();
1477         }
1478
1479         // check if files were found (probably an input error if not)
1480         if (fileName.empty())
1481         {
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"));
1485                 error();
1486         }
1487
1488         if (hasWildcard)
1489                 printSeparatingLine();
1490 }
1491
1492 bool ASConsole::fileNameVectorIsEmpty() const
1493 {
1494         return fileNameVector.empty();
1495 }
1496
1497 bool ASConsole::isOption(const string& arg, const char* op)
1498 {
1499         return arg.compare(op) == 0;
1500 }
1501
1502 bool ASConsole::isOption(const string& arg, const char* a, const char* b)
1503 {
1504         return (isOption(arg, a) || isOption(arg, b));
1505 }
1506
1507 bool ASConsole::isParamOption(const string& arg, const char* option)
1508 {
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]))
1513                         retVal = false;
1514         return retVal;
1515 }
1516
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)
1522 {
1523         bool retVal = false;
1524
1525         // read the exclude vector checking for a match
1526         for (size_t i = 0; i < excludeVector.size(); i++)
1527         {
1528                 string exclude = excludeVector[i];
1529
1530                 if (subPath.length() < exclude.length())
1531                         continue;
1532
1533                 size_t compareStart = subPath.length() - exclude.length();
1534                 // subPath compare must start with a directory name
1535                 if (compareStart > 0)
1536                 {
1537                         char lastPathChar = subPath[compareStart - 1];
1538                         if (lastPathChar != g_fileSeparator)
1539                                 continue;
1540                 }
1541
1542                 string compare = subPath.substr(compareStart);
1543                 if (!g_isCaseSensitive)
1544                 {
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]);
1550                 }
1551                 // compare sub directory to exclude data - must check them all
1552                 if (compare == exclude)
1553                 {
1554                         excludeHitsVector[i] = true;
1555                         retVal = true;
1556                         break;
1557                 }
1558         }
1559         return retVal;
1560 }
1561
1562 void ASConsole::printHelp() const
1563 {
1564         cout << endl;
1565         cout << "                     Artistic Style " << g_version << endl;
1566         cout << "                     Maintained by: Jim Pattee\n";
1567         cout << "                     Original Author: Tal Davidson\n";
1568         cout << endl;
1569         cout << "Usage:\n";
1570         cout << "------\n";
1571         cout << "            astyle [OPTIONS] File1 File2 File3 [...]\n";
1572         cout << endl;
1573         cout << "            astyle [OPTIONS] < Original > Beautified\n";
1574         cout << endl;
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";
1578         cout << endl;
1579         cout << "    Wildcards (* and ?) may be used in the filename.\n";
1580         cout << "    A \'recursive\' option can process directories recursively.\n";
1581         cout << endl;
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";
1586         cout << endl;
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";
1593         cout << endl;
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";
1608         cout << endl;
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";
1614         cout << endl;
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";
1618         cout << endl;
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";
1624         cout << endl;
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";
1628         cout << endl;
1629         cout << "    --style=java  OR  --style=attach  OR  -A2\n";
1630         cout << "    Java style formatting/indenting.\n";
1631         cout << "    Attached braces.\n";
1632         cout << endl;
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";
1636         cout << endl;
1637         cout << "    --style=stroustrup  OR  -A4\n";
1638         cout << "    Stroustrup style formatting/indenting.\n";
1639         cout << "    Linux braces.\n";
1640         cout << endl;
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";
1645         cout << endl;
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";
1649         cout << endl;
1650         cout << "    --style=banner  OR  -A6\n";
1651         cout << "    Banner style formatting/indenting.\n";
1652         cout << "    Attached, indented braces.\n";
1653         cout << endl;
1654         cout << "    --style=gnu  OR  -A7\n";
1655         cout << "    GNU style formatting/indenting.\n";
1656         cout << "    Broken braces, indented blocks.\n";
1657         cout << endl;
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";
1661         cout << endl;
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";
1665         cout << endl;
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";
1669         cout << endl;
1670         cout << "    --style=google  OR  -A14\n";
1671         cout << "    Google style formatting/indenting.\n";
1672         cout << "    Attached braces, indented class modifiers.\n";
1673         cout << endl;
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";
1678         cout << endl;
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";
1683         cout << endl;
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";
1688         cout << endl;
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";
1694         cout << endl;
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";
1698         cout << endl;
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";
1703         cout << endl;
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";
1708         cout << endl;
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";
1713         cout << endl;
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";
1718         cout << endl;
1719         cout << "    --attach-classes  OR  -xc\n";
1720         cout << "    Attach braces to a class statement.\n";
1721         cout << endl;
1722         cout << "    --attach-inlines  OR  -xl\n";
1723         cout << "    Attach braces to class inline function definitions.\n";
1724         cout << endl;
1725         cout << "    --attach-extern-c  OR  -xk\n";
1726         cout << "    Attach braces to an extern \"C\" statement.\n";
1727         cout << endl;
1728         cout << "    --attach-closing-while  OR  -xV\n";
1729         cout << "    Attach closing while of do-while to the closing brace.\n";
1730         cout << endl;
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";
1735         cout << endl;
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";
1740         cout << endl;
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";
1744         cout << endl;
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";
1748         cout << endl;
1749         cout << "    --indent-namespaces  OR  -N\n";
1750         cout << "    Indent the contents of namespace blocks.\n";
1751         cout << endl;
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";
1755         cout << endl;
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";
1760         cout << endl;
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";
1765         cout << endl;
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";
1769         cout << endl;
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";
1773         cout << endl;
1774         cout << "    --indent-preproc-define  OR  -w\n";
1775         cout << "    Indent multi-line preprocessor #define statements.\n";
1776         cout << endl;
1777         cout << "    --indent-col1-comments  OR  -Y\n";
1778         cout << "    Indent line comments that start in column one.\n";
1779         cout << endl;
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";
1789         cout << endl;
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";
1795         cout << endl;
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";
1800         cout << endl;
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";
1804         cout << endl;
1805         cout << "    --pad-oper  OR  -p\n";
1806         cout << "    Insert space padding around operators.\n";
1807         cout << endl;
1808         cout << "    --pad-comma  OR  -xg\n";
1809         cout << "    Insert space padding after commas.\n";
1810         cout << endl;
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";
1814         cout << endl;
1815         cout << "    --pad-paren-out  OR  -d\n";
1816         cout << "    Insert space padding around parenthesis on the outside only.\n";
1817         cout << endl;
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";
1821         cout << endl;
1822         cout << "    --pad-paren-in  OR  -D\n";
1823         cout << "    Insert space padding around parenthesis on the inside only.\n";
1824         cout << endl;
1825         cout << "    --pad-header  OR  -H\n";
1826         cout << "    Insert space padding after paren headers (e.g. 'if', 'for'...).\n";
1827         cout << endl;
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";
1831         cout << endl;
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";
1835         cout << endl;
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";
1839         cout << endl;
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";
1846         cout << endl;
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";
1854         cout << endl;
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";
1861         cout << endl;
1862         cout << "    --break-elseifs  OR  -e\n";
1863         cout << "    Break 'else if()' statements into two different lines.\n";
1864         cout << endl;
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";
1868         cout << endl;
1869         cout << "    --add-braces  OR  -j\n";
1870         cout << "    Add braces to unbraced one line conditional statements.\n";
1871         cout << endl;
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";
1875         cout << endl;
1876         cout << "    --remove-braces  OR  -xj\n";
1877         cout << "    Remove braces from a braced one line conditional statements.\n";
1878         cout << endl;
1879         cout << "    --keep-one-line-blocks  OR  -O\n";
1880         cout << "    Don't break blocks residing completely on one line.\n";
1881         cout << endl;
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";
1885         cout << endl;
1886         cout << "    --convert-tabs  OR  -c\n";
1887         cout << "    Convert tabs to the appropriate number of spaces.\n";
1888         cout << endl;
1889         cout << "    --close-templates  OR  -xy\n";
1890         cout << "    Close ending angle brackets on template definitions.\n";
1891         cout << endl;
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";
1895         cout << endl;
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";
1904         cout << endl;
1905         cout << "    --mode=c\n";
1906         cout << "    Indent a C or C++ source file (this is the default).\n";
1907         cout << endl;
1908         cout << "    --mode=java\n";
1909         cout << "    Indent a Java source file.\n";
1910         cout << endl;
1911         cout << "    --mode=cs\n";
1912         cout << "    Indent a C# source file.\n";
1913         cout << endl;
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";
1919         cout << endl;
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";
1923         cout << endl;
1924         cout << "    --pad-return-type  OR  -xq\n";
1925         cout << "    Insert space padding after the Objective-C return type.\n";
1926         cout << endl;
1927         cout << "    --unpad-return-type  OR  -xr\n";
1928         cout << "    Remove all space padding after the Objective-C return type.\n";
1929         cout << endl;
1930         cout << "    --pad-param-type  OR  -xS\n";
1931         cout << "    Insert space padding after the Objective-C return type.\n";
1932         cout << endl;
1933         cout << "    --unpad-param-type  OR  -xs\n";
1934         cout << "    Remove all space padding after the Objective-C return type.\n";
1935         cout << endl;
1936         cout << "    --align-method-colon  OR  -xM\n";
1937         cout << "    Align the colons in an Objective-C method definition.\n";
1938         cout << endl;
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";
1945         cout << endl;
1946         cout << "Other Options:\n";
1947         cout << "--------------\n";
1948         cout << "    --suffix=####\n";
1949         cout << "    Append the suffix #### instead of '.orig' to original filename.\n";
1950         cout << endl;
1951         cout << "    --suffix=none  OR  -n\n";
1952         cout << "    Do not retain a backup of the original file.\n";
1953         cout << endl;
1954         cout << "    --recursive  OR  -r  OR  -R\n";
1955         cout << "    Process subdirectories recursively.\n";
1956         cout << endl;
1957         cout << "    --dry-run\n";
1958         cout << "    Perform a trial run with no changes made to check for formatting.\n";
1959         cout << endl;
1960         cout << "    --exclude=####\n";
1961         cout << "    Specify a file or directory #### to be excluded from processing.\n";
1962         cout << endl;
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";
1966         cout << endl;
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";
1970         cout << endl;
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";
1974         cout << endl;
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";
1978         cout << endl;
1979         cout << "    --verbose  OR  -v\n";
1980         cout << "    Verbose mode. Extra informational messages will be displayed.\n";
1981         cout << endl;
1982         cout << "    --formatted  OR  -Q\n";
1983         cout << "    Formatted display mode. Display only the files that have been\n";
1984         cout << "    formatted.\n";
1985         cout << endl;
1986         cout << "    --quiet  OR  -q\n";
1987         cout << "    Quiet mode. Suppress all output except error messages.\n";
1988         cout << endl;
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";
1994         cout << endl;
1995         cout << "Command Line Only:\n";
1996         cout << "------------------\n";
1997         cout << "    --options=####\n";
1998         cout << "    Specify an options file #### to read and use.\n";
1999         cout << endl;
2000         cout << "    --options=none\n";
2001         cout << "    Disable the default options file.\n";
2002         cout << "    Only the command-line parameters will be used.\n";
2003         cout << endl;
2004         cout << "    --ascii  OR  -I\n";
2005         cout << "    The displayed output will be ascii characters only.\n";
2006         cout << endl;
2007         cout << "    --version  OR  -V\n";
2008         cout << "    Print version number.\n";
2009         cout << endl;
2010         cout << "    --help  OR  -h  OR  -?\n";
2011         cout << "    Print this help message.\n";
2012         cout << endl;
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";
2016         cout << endl;
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";
2021         cout << endl;
2022         cout << endl;
2023 }
2024
2025 /**
2026  * Process files in the fileNameVector.
2027  */
2028 void ASConsole::processFiles()
2029 {
2030         if (isVerbose)
2031                 printVerboseHeader();
2032
2033         clock_t startTime = clock();     // start time of file formatting
2034
2035         // loop thru input fileNameVector and process the files
2036         for (size_t i = 0; i < fileNameVector.size(); i++)
2037         {
2038                 getFilePaths(fileNameVector[i]);
2039
2040                 // loop thru fileName vector formatting the files
2041                 for (size_t j = 0; j < fileName.size(); j++)
2042                         formatFile(fileName[j]);
2043         }
2044
2045         // files are processed, display stats
2046         if (isVerbose)
2047                 printVerboseStats(startTime);
2048 }
2049
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)
2053 {
2054         string arg;
2055         bool ok = true;
2056         bool shouldParseOptionsFile = true;
2057
2058         // get command line options
2059         for (size_t i = 0; i < argvOptions.size(); i++)
2060         {
2061                 arg = argvOptions[i];
2062
2063                 if ( isOption(arg, "-I" )
2064                         || isOption(arg, "--ascii") )
2065                 {
2066                         useAscii = true;
2067                         setlocale(LC_ALL, "C");         // use English decimal indicator
2068                         localizer.setLanguageFromName("en");
2069                 }
2070                 else if ( isOption(arg, "--options=none") )
2071                 {
2072                         shouldParseOptionsFile = false;
2073                 }
2074                 else if ( isParamOption(arg, "--options=") )
2075                 {
2076                         optionsFileName = getParam(arg, "--options=");
2077                         optionsFileRequired = true;
2078                         if (optionsFileName.empty())
2079                                 setOptionsFileName(" ");
2080                 }
2081                 else if ( isOption(arg, "-h")
2082                           || isOption(arg, "--help")
2083                           || isOption(arg, "-?") )
2084                 {
2085                         printHelp();
2086                         exit(EXIT_SUCCESS);
2087                 }
2088                 else if ( isOption(arg, "-!")
2089                           || isOption(arg, "--html") )
2090                 {
2091                         launchDefaultBrowser();
2092                         exit(EXIT_SUCCESS);
2093                 }
2094                 else if ( isParamOption(arg, "--html=") )
2095                 {
2096                         string htmlFilePath = getParam(arg, "--html=");
2097                         launchDefaultBrowser(htmlFilePath.c_str());
2098                         exit(EXIT_SUCCESS);
2099                 }
2100                 else if ( isOption(arg, "-V" )
2101                           || isOption(arg, "--version") )
2102                 {
2103                         printf("Artistic Style Version %s\n", g_version);
2104                         exit(EXIT_SUCCESS);
2105                 }
2106                 else if (arg[0] == '-')
2107                 {
2108                         optionsVector.emplace_back(arg);
2109                 }
2110                 else // file-name
2111                 {
2112                         standardizePath(arg);
2113                         fileNameVector.emplace_back(arg);
2114                 }
2115         }
2116
2117         // get options file path and name
2118         if (shouldParseOptionsFile)
2119         {
2120                 if (optionsFileName.empty())
2121                 {
2122                         char* env = getenv("ARTISTIC_STYLE_OPTIONS");
2123                         if (env != nullptr)
2124                                 setOptionsFileName(env);
2125                 }
2126                 if (optionsFileName.empty())
2127                 {
2128                         char* env = getenv("HOME");
2129                         if (env != nullptr)
2130                                 setOptionsFileName(string(env) + "/.astylerc");
2131                 }
2132                 if (optionsFileName.empty())
2133                 {
2134                         char* env = getenv("USERPROFILE");
2135                         if (env != nullptr)
2136                                 setOptionsFileName(string(env) + "/astylerc");
2137                 }
2138                 if (!optionsFileName.empty())
2139                         standardizePath(optionsFileName);
2140         }
2141
2142         // create the options file vector and parse the options for errors
2143         ASOptions options(formatter, *this);
2144         if (!optionsFileName.empty())
2145         {
2146                 ifstream optionsIn(optionsFileName.c_str());
2147                 if (optionsIn)
2148                 {
2149                         options.importOptions(optionsIn, fileOptionsVector);
2150                         ok = options.parseOptions(fileOptionsVector,
2151                                                   string(_("Invalid option file options:")));
2152                 }
2153                 else
2154                 {
2155                         if (optionsFileRequired)
2156                                 error(_("Cannot open options file"), optionsFileName.c_str());
2157                         optionsFileName.clear();
2158                 }
2159                 optionsIn.close();
2160         }
2161         if (!ok)
2162         {
2163                 (*errorStream) << options.getOptionErrors() << endl;
2164                 (*errorStream) << _("For help on options type 'astyle -h'") << endl;
2165                 error();
2166         }
2167
2168         // parse the command line options vector for errors
2169         ok = options.parseOptions(optionsVector,
2170                                   string(_("Invalid command line options:")));
2171         if (!ok)
2172         {
2173                 (*errorStream) << options.getOptionErrors() << endl;
2174                 (*errorStream) << _("For help on options type 'astyle -h'") << endl;
2175                 error();
2176         }
2177 }
2178
2179 // remove a file and check for an error
2180 void ASConsole::removeFile(const char* fileName_, const char* errMsg) const
2181 {
2182         if (remove(fileName_) != 0)
2183         {
2184                 if (errno == ENOENT)        // no file is OK
2185                         errno = 0;
2186                 if (errno)
2187                 {
2188                         perror("errno message");
2189                         error(errMsg, fileName_);
2190                 }
2191         }
2192 }
2193
2194 // rename a file and check for an error
2195 void ASConsole::renameFile(const char* oldFileName, const char* newFileName, const char* errMsg) const
2196 {
2197         int result = rename(oldFileName, newFileName);
2198         if (result != 0)
2199         {
2200                 // if file still exists the remove needs more time - retry
2201                 if (errno == EEXIST)
2202                 {
2203                         errno = 0;
2204                         waitForRemove(newFileName);
2205                         result = rename(oldFileName, newFileName);
2206                 }
2207                 if (result != 0)
2208                 {
2209                         perror("errno message");
2210                         error(errMsg, oldFileName);
2211                 }
2212         }
2213 }
2214
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
2219 {
2220 #ifdef __VMS
2221         struct FAB fab;
2222         struct NAML naml;
2223         char less[NAML$C_MAXRSS];
2224         char sess[NAM$C_MAXRSS];
2225         int r0_status;
2226
2227         // If we are on a VMS system, translate VMS style filenames to unix
2228         // style.
2229         fab = cc$rms_fab;
2230         fab.fab$l_fna = (char*) -1;        // *NOPAD*
2231         fab.fab$b_fns = 0;
2232         fab.fab$l_naml = &naml;
2233         naml = cc$rms_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)
2244         {
2245                 error("File syntax error", path.c_str());
2246         }
2247         else
2248         {
2249                 if (!$VMS_STATUS_SUCCESS(r0_status))
2250                 {
2251                         (void)lib$signal (r0_status);
2252                 }
2253         }
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)
2257         {
2258                 path = decc$translate_vms (less);
2259         }
2260         else
2261         {
2262                 path = decc$translate_vms(sess);
2263         }
2264 #endif /* __VMS */
2265
2266         // make sure separators are correct type (Windows or Linux)
2267         for (size_t i = 0; i < path.length(); i++)
2268         {
2269                 i = path.find_first_of("/\\", i);
2270                 if (i == string::npos)
2271                         break;
2272                 path[i] = g_fileSeparator;
2273         }
2274         // remove beginning separator if requested
2275         if (removeBeginningSeparator && (path[0] == g_fileSeparator))
2276                 path.erase(0, 1);
2277 }
2278
2279 void ASConsole::printMsg(const char* msg, const string& data) const
2280 {
2281         if (isQuiet)
2282                 return;
2283         printf(msg, data.c_str());
2284 }
2285
2286 void ASConsole::printSeparatingLine() const
2287 {
2288         string line;
2289         for (size_t i = 0; i < 60; i++)
2290                 line.append("-");
2291         printMsg("%s\n", line);
2292 }
2293
2294 void ASConsole::printVerboseHeader() const
2295 {
2296         assert(isVerbose);
2297         if (isQuiet)
2298                 return;
2299         // get the date
2300         time_t lt;
2301         char str[20];
2302         lt = time(nullptr);
2303         struct tm* ptr = localtime(&lt);
2304         strftime(str, 20, "%x", ptr);
2305         // print the header
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, ' ');
2310         header.append(str);
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());
2316 }
2317
2318 void ASConsole::printVerboseStats(clock_t startTime) const
2319 {
2320         assert(isVerbose);
2321         if (isQuiet)
2322                 return;
2323         if (hasWildcard)
2324                 printSeparatingLine();
2325         string formatted = getNumberFormat(filesFormatted);
2326         string unchanged = getNumberFormat(filesUnchanged);
2327         printf(_(" %s formatted   %s unchanged   "), formatted.c_str(), unchanged.c_str());
2328
2329         // show processing time
2330         clock_t stopTime = clock();
2331         double secs = (stopTime - startTime) / double (CLOCKS_PER_SEC);
2332         if (secs < 60)
2333         {
2334                 if (secs < 2.0)
2335                         printf("%.2f", secs);
2336                 else if (secs < 20.0)
2337                         printf("%.1f", secs);
2338                 else
2339                         printf("%.0f", secs);
2340                 printf("%s", _(" seconds   "));
2341         }
2342         else
2343         {
2344                 // show minutes and seconds if time is greater than one minute
2345                 int min = (int) secs / 60;
2346                 secs -= min * 60;
2347                 int minsec = int (secs + .5);
2348                 printf(_("%d min %d sec   "), min, minsec);
2349         }
2350
2351         string lines = getNumberFormat(linesOut);
2352         printf(_("%s lines\n"), lines.c_str());
2353 }
2354
2355 void ASConsole::sleep(int seconds) const
2356 {
2357         clock_t endwait;
2358         endwait = clock_t (clock () + seconds * CLOCKS_PER_SEC);
2359         while (clock() < endwait) {}
2360 }
2361
2362 bool ASConsole::stringEndsWith(const string& str, const string& suffix) const
2363 {
2364         int strIndex = (int) str.length() - 1;
2365         int suffixIndex = (int) suffix.length() - 1;
2366
2367         while (strIndex >= 0 && suffixIndex >= 0)
2368         {
2369                 if (tolower(str[strIndex]) != tolower(suffix[suffixIndex]))
2370                         return false;
2371
2372                 --strIndex;
2373                 --suffixIndex;
2374         }
2375         // suffix longer than string
2376         if (strIndex < 0 && suffixIndex >= 0)
2377                 return false;
2378         return true;
2379 }
2380
2381 void ASConsole::updateExcludeVector(const string& suffixParam)
2382 {
2383         excludeVector.emplace_back(suffixParam);
2384         standardizePath(excludeVector.back(), true);
2385         excludeHitsVector.push_back(false);
2386 }
2387
2388 int ASConsole::waitForRemove(const char* newFileName) const
2389 {
2390         struct stat stBuf;
2391         int seconds;
2392         // sleep a max of 20 seconds for the remove
2393         for (seconds = 1; seconds <= 20; seconds++)
2394         {
2395                 sleep(1);
2396                 if (stat(newFileName, &stBuf) != 0)
2397                         break;
2398         }
2399         errno = 0;
2400         return seconds;
2401 }
2402
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
2407 {
2408         const char* cp = nullptr, *mp = nullptr;
2409         bool cmpval;
2410
2411         while ((*data) && (*wild != '*'))
2412         {
2413                 if (!g_isCaseSensitive)
2414                         cmpval = (tolower(*wild) != tolower(*data)) && (*wild != '?');
2415                 else
2416                         cmpval = (*wild != *data) && (*wild != '?');
2417
2418                 if (cmpval)
2419                 {
2420                         return 0;
2421                 }
2422                 wild++;
2423                 data++;
2424         }
2425
2426         while (*data)
2427         {
2428                 if (*wild == '*')
2429                 {
2430                         if (!*++wild)
2431                         {
2432                                 return 1;
2433                         }
2434                         mp = wild;
2435                         cp = data + 1;
2436                 }
2437                 else
2438                 {
2439                         if (!g_isCaseSensitive)
2440                                 cmpval = (tolower(*wild) == tolower(*data) || (*wild == '?'));
2441                         else
2442                                 cmpval = (*wild == *data) || (*wild == '?');
2443
2444                         if (cmpval)
2445                         {
2446                                 wild++;
2447                                 data++;
2448                         }
2449                         else
2450                         {
2451                                 wild = mp;
2452                                 data = cp++;
2453                         }
2454                 }
2455         }
2456
2457         while (*wild == '*')
2458         {
2459                 wild++;
2460         }
2461         return !*wild;
2462 }
2463
2464 void ASConsole::writeFile(const string& fileName_, FileEncoding encoding, ostringstream& out) const
2465 {
2466         // save date accessed and date modified of original file
2467         struct stat stBuf;
2468         bool statErr = false;
2469         if (stat(fileName_.c_str(), &stBuf) == -1)
2470                 statErr = true;
2471
2472         // create a backup
2473         if (!noBackup)
2474         {
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");
2478         }
2479
2480         // write the output file
2481         ofstream fout(fileName_.c_str(), ios::binary | ios::trunc);
2482         if (!fout)
2483                 error("Cannot open output file", fileName_.c_str());
2484         if (encoding == UTF_16LE || encoding == UTF_16BE)
2485         {
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);
2494                 delete[] utf16Out;
2495         }
2496         else
2497                 fout << out.str();
2498
2499         fout.close();
2500
2501         // change date modified to original file date
2502         // Embarcadero must be linked with cw32mt not cw32
2503         if (preserveDate)
2504         {
2505                 if (!statErr)
2506                 {
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)
2513                                 statErr = true;
2514                 }
2515                 if (statErr)
2516                 {
2517                         perror("errno message");
2518                         (*errorStream) << "*********  Cannot preserve file date" << endl;
2519                 }
2520         }
2521 }
2522
2523 #else   // ASTYLE_LIB
2524
2525 //-----------------------------------------------------------------------------
2526 // ASLibrary class
2527 // used by shared object (DLL) calls
2528 //-----------------------------------------------------------------------------
2529
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)
2534 {
2535         const char* utf8In = convertUtf16ToUtf8(pSourceIn);
2536         if (utf8In == nullptr)
2537         {
2538                 fpErrorHandler(121, "Cannot convert input utf-16 to utf-8.");
2539                 return nullptr;
2540         }
2541         const char* utf8Options = convertUtf16ToUtf8(pOptions);
2542         if (utf8Options == nullptr)
2543         {
2544                 delete[] utf8In;
2545                 fpErrorHandler(122, "Cannot convert options utf-16 to utf-8.");
2546                 return nullptr;
2547         }
2548         // call the Artistic Style formatting function
2549         // cannot use the callers memory allocation here
2550         char* utf8Out = AStyleMain(utf8In,
2551                                    utf8Options,
2552                                    fpErrorHandler,
2553                                    ASLibrary::tempMemoryAllocation);
2554         // finished with these
2555         delete[] utf8In;
2556         delete[] utf8Options;
2557         utf8In = nullptr;
2558         utf8Options = nullptr;
2559         // AStyle error has already been sent
2560         if (utf8Out == nullptr)
2561                 return nullptr;
2562         // convert text to wide char and return it
2563         utf16_t* utf16Out = convertUtf8ToUtf16(utf8Out, fpMemoryAlloc);
2564         delete[] utf8Out;
2565         utf8Out = nullptr;
2566         if (utf16Out == nullptr)
2567         {
2568                 fpErrorHandler(123, "Cannot convert output utf-8 to utf-16.");
2569                 return nullptr;
2570         }
2571         return utf16Out;
2572 }
2573
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)
2577 {
2578         char* buffer = new (nothrow) char[memoryNeeded];
2579         return buffer;
2580 }
2581
2582 /**
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.
2586  */
2587 utf16_t* ASLibrary::convertUtf8ToUtf16(const char* utf8In, fpAlloc fpMemoryAlloc) const
2588 {
2589         if (utf8In == nullptr)
2590                 return 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)
2598                 return nullptr;
2599 #ifdef NDEBUG
2600         utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
2601 #else
2602         size_t utf16Len = utf8_16.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
2603         assert(utf16Len == utf16Size);
2604 #endif
2605         assert(utf16Size == (utf8_16.utf16len(reinterpret_cast<utf16_t*>(utf16Out)) + 1) * sizeof(utf16_t));
2606         return reinterpret_cast<utf16_t*>(utf16Out);
2607 }
2608
2609 /**
2610  * Convert utf16 strings to utf-8.
2611  * The calling function must check for errors and delete the
2612  * allocated memory.
2613  */
2614 char* ASLibrary::convertUtf16ToUtf8(const utf16_t* utf16In) const
2615 {
2616         if (utf16In == nullptr)
2617                 return 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)
2625                 return nullptr;
2626 #ifdef NDEBUG
2627         utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
2628 #else
2629         size_t utf8Len = utf8_16.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
2630         assert(utf8Len == utf8Size);
2631 #endif
2632         assert(utf8Size == strlen(utf8Out) + 1);
2633         return utf8Out;
2634 }
2635
2636 #endif  // ASTYLE_LIB
2637
2638 //-----------------------------------------------------------------------------
2639 // ASOptions class
2640 // used by both console and library builds
2641 //-----------------------------------------------------------------------------
2642
2643 #ifdef ASTYLE_LIB
2644 ASOptions::ASOptions(ASFormatter& formatterArg)
2645         : formatter(formatterArg)
2646 { }
2647 #else
2648 ASOptions::ASOptions(ASFormatter& formatterArg, ASConsole& consoleArg)
2649         : formatter(formatterArg), console(consoleArg)
2650 { }
2651 #endif
2652
2653 /**
2654  * parse the options vector
2655  * optionsVector can be either a fileOptionsVector (options file) or an optionsVector (command line)
2656  *
2657  * @return        true if no errors, false if errors
2658  */
2659 bool ASOptions::parseOptions(vector<string>& optionsVector, const string& errorInfo)
2660 {
2661         vector<string>::iterator option;
2662         string arg, subArg;
2663         optionErrors.clear();
2664
2665         for (option = optionsVector.begin(); option != optionsVector.end(); ++option)
2666         {
2667                 arg = *option;
2668
2669                 if (arg.compare(0, 2, "--") == 0)
2670                         parseOption(arg.substr(2), errorInfo);
2671                 else if (arg[0] == '-')
2672                 {
2673                         size_t i;
2674
2675                         for (i = 1; i < arg.length(); ++i)
2676                         {
2677                                 if (i > 1
2678                                         && isalpha((unsigned char)arg[i])
2679                                         && arg[i - 1] != 'x')
2680                                 {
2681                                         // parse the previous option in subArg
2682                                         parseOption(subArg, errorInfo);
2683                                         subArg = "";
2684                                 }
2685                                 // append the current option to subArg
2686                                 subArg.append(1, arg[i]);
2687                         }
2688                         // parse the last option
2689                         parseOption(subArg, errorInfo);
2690                         subArg = "";
2691                 }
2692                 else
2693                 {
2694                         parseOption(arg, errorInfo);
2695                         subArg = "";
2696                 }
2697         }
2698         if (optionErrors.str().length() > 0)
2699                 return false;
2700         return true;
2701 }
2702
2703 void ASOptions::parseOption(const string& arg, const string& errorInfo)
2704 {
2705         if ( isOption(arg, "style=allman") || isOption(arg, "style=bsd") || isOption(arg, "style=break") )
2706         {
2707                 formatter.setFormattingStyle(STYLE_ALLMAN);
2708         }
2709         else if ( isOption(arg, "style=java") || isOption(arg, "style=attach") )
2710         {
2711                 formatter.setFormattingStyle(STYLE_JAVA);
2712         }
2713         else if ( isOption(arg, "style=k&r") || isOption(arg, "style=kr") || isOption(arg, "style=k/r") )
2714         {
2715                 formatter.setFormattingStyle(STYLE_KR);
2716         }
2717         else if ( isOption(arg, "style=stroustrup") )
2718         {
2719                 formatter.setFormattingStyle(STYLE_STROUSTRUP);
2720         }
2721         else if ( isOption(arg, "style=whitesmith") )
2722         {
2723                 formatter.setFormattingStyle(STYLE_WHITESMITH);
2724         }
2725         else if ( isOption(arg, "style=vtk") )
2726         {
2727                 formatter.setFormattingStyle(STYLE_VTK);
2728         }
2729         else if ( isOption(arg, "style=banner") )
2730         {
2731                 formatter.setFormattingStyle(STYLE_BANNER);
2732         }
2733         else if ( isOption(arg, "style=gnu") )
2734         {
2735                 formatter.setFormattingStyle(STYLE_GNU);
2736         }
2737         else if ( isOption(arg, "style=linux") || isOption(arg, "style=knf") )
2738         {
2739                 formatter.setFormattingStyle(STYLE_LINUX);
2740         }
2741         else if ( isOption(arg, "style=horstmann") || isOption(arg, "style=run-in") )
2742         {
2743                 formatter.setFormattingStyle(STYLE_HORSTMANN);
2744         }
2745         else if ( isOption(arg, "style=1tbs") || isOption(arg, "style=otbs") )
2746         {
2747                 formatter.setFormattingStyle(STYLE_1TBS);
2748         }
2749         else if ( isOption(arg, "style=google") )
2750         {
2751                 formatter.setFormattingStyle(STYLE_GOOGLE);
2752         }
2753         else if (isOption(arg, "style=mozilla"))
2754         {
2755                 formatter.setFormattingStyle(STYLE_MOZILLA);
2756         }
2757         else if ( isOption(arg, "style=pico") )
2758         {
2759                 formatter.setFormattingStyle(STYLE_PICO);
2760         }
2761         else if ( isOption(arg, "style=lisp") || isOption(arg, "style=python") )
2762         {
2763                 formatter.setFormattingStyle(STYLE_LISP);
2764         }
2765         else if ( isParamOption(arg, "A") )
2766         {
2767                 int style = 0;
2768                 string styleParam = getParam(arg, "A");
2769                 if (styleParam.length() > 0)
2770                         style = atoi(styleParam.c_str());
2771                 if (style == 1)
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);
2801                 else
2802                         isOptionError(arg, errorInfo);
2803         }
2804         // must check for mode=cs before mode=c !!!
2805         else if ( isOption(arg, "mode=cs") )
2806         {
2807                 formatter.setSharpStyle();
2808                 formatter.setModeManuallySet(true);
2809         }
2810         else if ( isOption(arg, "mode=c") )
2811         {
2812                 formatter.setCStyle();
2813                 formatter.setModeManuallySet(true);
2814         }
2815         else if ( isOption(arg, "mode=java") )
2816         {
2817                 formatter.setJavaStyle();
2818                 formatter.setModeManuallySet(true);
2819         }
2820         else if ( isParamOption(arg, "t", "indent=tab=") )
2821         {
2822                 int spaceNum = 4;
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);
2828                 else
2829                 {
2830                         formatter.setTabIndentation(spaceNum, false);
2831                 }
2832         }
2833         else if ( isOption(arg, "indent=tab") )
2834         {
2835                 formatter.setTabIndentation(4);
2836         }
2837         else if ( isParamOption(arg, "T", "indent=force-tab=") )
2838         {
2839                 int spaceNum = 4;
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);
2845                 else
2846                 {
2847                         formatter.setTabIndentation(spaceNum, true);
2848                 }
2849         }
2850         else if ( isOption(arg, "indent=force-tab") )
2851         {
2852                 formatter.setTabIndentation(4, true);
2853         }
2854         else if ( isParamOption(arg, "xT", "indent=force-tab-x=") )
2855         {
2856                 int tabNum = 8;
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);
2862                 else
2863                 {
2864                         formatter.setForceTabXIndentation(tabNum);
2865                 }
2866         }
2867         else if ( isOption(arg, "indent=force-tab-x") )
2868         {
2869                 formatter.setForceTabXIndentation(8);
2870         }
2871         else if ( isParamOption(arg, "s", "indent=spaces=") )
2872         {
2873                 int spaceNum = 4;
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);
2879                 else
2880                 {
2881                         formatter.setSpaceIndentation(spaceNum);
2882                 }
2883         }
2884         else if ( isOption(arg, "indent=spaces") )
2885         {
2886                 formatter.setSpaceIndentation(4);
2887         }
2888         else if (isParamOption(arg, "xt", "indent-continuation="))
2889         {
2890                 int contIndent = 1;
2891                 string contIndentParam = getParam(arg, "xt", "indent-continuation=");
2892                 if (contIndentParam.length() > 0)
2893                         contIndent = atoi(contIndentParam.c_str());
2894                 if (contIndent < 0)
2895                         isOptionError(arg, errorInfo);
2896                 else if (contIndent > 4)
2897                         isOptionError(arg, errorInfo);
2898                 else
2899                         formatter.setContinuationIndentation(contIndent);
2900         }
2901         else if ( isParamOption(arg, "m", "min-conditional-indent=") )
2902         {
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);
2909                 else
2910                         formatter.setMinConditionalIndentOption(minIndent);
2911         }
2912         else if ( isParamOption(arg, "M", "max-continuation-indent=") )
2913         {
2914                 int maxIndent = 40;
2915                 string maxIndentParam = getParam(arg, "M", "max-continuation-indent=");
2916                 if (maxIndentParam.length() > 0)
2917                         maxIndent = atoi(maxIndentParam.c_str());
2918                 if (maxIndent < 40)
2919                         isOptionError(arg, errorInfo);
2920                 else if (maxIndent > 120)
2921                         isOptionError(arg, errorInfo);
2922                 else
2923                         formatter.setMaxContinuationIndentLength(maxIndent);
2924         }
2925         else if ( isOption(arg, "N", "indent-namespaces") )
2926         {
2927                 formatter.setNamespaceIndent(true);
2928         }
2929         else if ( isOption(arg, "C", "indent-classes") )
2930         {
2931                 formatter.setClassIndent(true);
2932         }
2933         else if ( isOption(arg, "xG", "indent-modifiers") )
2934         {
2935                 formatter.setModifierIndent(true);
2936         }
2937         else if ( isOption(arg, "S", "indent-switches") )
2938         {
2939                 formatter.setSwitchIndent(true);
2940         }
2941         else if ( isOption(arg, "K", "indent-cases") )
2942         {
2943                 formatter.setCaseIndent(true);
2944         }
2945         else if ( isOption(arg, "xU", "indent-after-parens") )
2946         {
2947                 formatter.setAfterParenIndent(true);
2948         }
2949         else if ( isOption(arg, "L", "indent-labels") )
2950         {
2951                 formatter.setLabelIndent(true);
2952         }
2953         else if (isOption(arg, "xW", "indent-preproc-block"))
2954         {
2955                 formatter.setPreprocBlockIndent(true);
2956         }
2957         else if ( isOption(arg, "w", "indent-preproc-define") )
2958         {
2959                 formatter.setPreprocDefineIndent(true);
2960         }
2961         else if ( isOption(arg, "xw", "indent-preproc-cond") )
2962         {
2963                 formatter.setPreprocConditionalIndent(true);
2964         }
2965         else if ( isOption(arg, "y", "break-closing-braces") )
2966         {
2967                 formatter.setBreakClosingHeaderBracesMode(true);
2968         }
2969         else if ( isOption(arg, "O", "keep-one-line-blocks") )
2970         {
2971                 formatter.setBreakOneLineBlocksMode(false);
2972         }
2973         else if ( isOption(arg, "o", "keep-one-line-statements") )
2974         {
2975                 formatter.setBreakOneLineStatementsMode(false);
2976         }
2977         else if ( isOption(arg, "P", "pad-paren") )
2978         {
2979                 formatter.setParensOutsidePaddingMode(true);
2980                 formatter.setParensInsidePaddingMode(true);
2981         }
2982         else if ( isOption(arg, "d", "pad-paren-out") )
2983         {
2984                 formatter.setParensOutsidePaddingMode(true);
2985         }
2986         else if ( isOption(arg, "xd", "pad-first-paren-out") )
2987         {
2988                 formatter.setParensFirstPaddingMode(true);
2989         }
2990         else if ( isOption(arg, "D", "pad-paren-in") )
2991         {
2992                 formatter.setParensInsidePaddingMode(true);
2993         }
2994         else if ( isOption(arg, "H", "pad-header") )
2995         {
2996                 formatter.setParensHeaderPaddingMode(true);
2997         }
2998         else if ( isOption(arg, "U", "unpad-paren") )
2999         {
3000                 formatter.setParensUnPaddingMode(true);
3001         }
3002         else if ( isOption(arg, "p", "pad-oper") )
3003         {
3004                 formatter.setOperatorPaddingMode(true);
3005         }
3006         else if (isOption(arg, "xg", "pad-comma"))
3007         {
3008                 formatter.setCommaPaddingMode(true);
3009         }
3010         else if ( isOption(arg, "xe", "delete-empty-lines") )
3011         {
3012                 formatter.setDeleteEmptyLinesMode(true);
3013         }
3014         else if ( isOption(arg, "E", "fill-empty-lines") )
3015         {
3016                 formatter.setEmptyLineFill(true);
3017         }
3018         else if ( isOption(arg, "c", "convert-tabs") )
3019         {
3020                 formatter.setTabSpaceConversionMode(true);
3021         }
3022         else if ( isOption(arg, "xy", "close-templates") )
3023         {
3024                 formatter.setCloseTemplatesMode(true);
3025         }
3026         else if ( isOption(arg, "F", "break-blocks=all") )
3027         {
3028                 formatter.setBreakBlocksMode(true);
3029                 formatter.setBreakClosingHeaderBlocksMode(true);
3030         }
3031         else if ( isOption(arg, "f", "break-blocks") )
3032         {
3033                 formatter.setBreakBlocksMode(true);
3034         }
3035         else if ( isOption(arg, "e", "break-elseifs") )
3036         {
3037                 formatter.setBreakElseIfsMode(true);
3038         }
3039         else if ( isOption(arg, "xb", "break-one-line-headers") )
3040         {
3041                 formatter.setBreakOneLineHeadersMode(true);
3042         }
3043         else if ( isOption(arg, "j", "add-braces") )
3044         {
3045                 formatter.setAddBracesMode(true);
3046         }
3047         else if ( isOption(arg, "J", "add-one-line-braces") )
3048         {
3049                 formatter.setAddOneLineBracesMode(true);
3050         }
3051         else if ( isOption(arg, "xj", "remove-braces") )
3052         {
3053                 formatter.setRemoveBracesMode(true);
3054         }
3055         else if ( isOption(arg, "Y", "indent-col1-comments") )
3056         {
3057                 formatter.setIndentCol1CommentsMode(true);
3058         }
3059         else if ( isOption(arg, "align-pointer=type") )
3060         {
3061                 formatter.setPointerAlignment(PTR_ALIGN_TYPE);
3062         }
3063         else if ( isOption(arg, "align-pointer=middle") )
3064         {
3065                 formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
3066         }
3067         else if ( isOption(arg, "align-pointer=name") )
3068         {
3069                 formatter.setPointerAlignment(PTR_ALIGN_NAME);
3070         }
3071         else if ( isParamOption(arg, "k") )
3072         {
3073                 int align = 0;
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);
3085         }
3086         else if ( isOption(arg, "align-reference=none") )
3087         {
3088                 formatter.setReferenceAlignment(REF_ALIGN_NONE);
3089         }
3090         else if ( isOption(arg, "align-reference=type") )
3091         {
3092                 formatter.setReferenceAlignment(REF_ALIGN_TYPE);
3093         }
3094         else if ( isOption(arg, "align-reference=middle") )
3095         {
3096                 formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
3097         }
3098         else if ( isOption(arg, "align-reference=name") )
3099         {
3100                 formatter.setReferenceAlignment(REF_ALIGN_NAME);
3101         }
3102         else if ( isParamOption(arg, "W") )
3103         {
3104                 int align = 0;
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);
3118         }
3119         else if ( isParamOption(arg, "max-code-length=") )
3120         {
3121                 int maxLength = 50;
3122                 string maxLengthParam = getParam(arg, "max-code-length=");
3123                 if (maxLengthParam.length() > 0)
3124                         maxLength = atoi(maxLengthParam.c_str());
3125                 if (maxLength < 50)
3126                         isOptionError(arg, errorInfo);
3127                 else if (maxLength > 200)
3128                         isOptionError(arg, errorInfo);
3129                 else
3130                         formatter.setMaxCodeLength(maxLength);
3131         }
3132         else if ( isParamOption(arg, "xC") )
3133         {
3134                 int maxLength = 50;
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);
3140                 else
3141                         formatter.setMaxCodeLength(maxLength);
3142         }
3143         else if ( isOption(arg, "xL", "break-after-logical") )
3144         {
3145                 formatter.setBreakAfterMode(true);
3146         }
3147         else if ( isOption(arg, "xc", "attach-classes") )
3148         {
3149                 formatter.setAttachClass(true);
3150         }
3151         else if ( isOption(arg, "xV", "attach-closing-while") )
3152         {
3153                 formatter.setAttachClosingWhile(true);
3154         }
3155         else if ( isOption(arg, "xk", "attach-extern-c") )
3156         {
3157                 formatter.setAttachExternC(true);
3158         }
3159         else if ( isOption(arg, "xn", "attach-namespaces") )
3160         {
3161                 formatter.setAttachNamespace(true);
3162         }
3163         else if ( isOption(arg, "xl", "attach-inlines") )
3164         {
3165                 formatter.setAttachInline(true);
3166         }
3167         else if ( isOption(arg, "xp", "remove-comment-prefix") )
3168         {
3169                 formatter.setStripCommentPrefix(true);
3170         }
3171         // Objective-C options
3172         else if ( isOption(arg, "xQ", "pad-method-prefix") )
3173         {
3174                 formatter.setMethodPrefixPaddingMode(true);
3175         }
3176         else if ( isOption(arg, "xR", "unpad-method-prefix") )
3177         {
3178                 formatter.setMethodPrefixUnPaddingMode(true);
3179         }
3180         else if (isOption(arg, "xq", "pad-return-type"))
3181         {
3182                 formatter.setReturnTypePaddingMode(true);
3183         }
3184         else if (isOption(arg, "xr", "unpad-return-type"))
3185         {
3186                 formatter.setReturnTypeUnPaddingMode(true);
3187         }
3188         else if (isOption(arg, "xS", "pad-param-type"))
3189         {
3190                 formatter.setParamTypePaddingMode(true);
3191         }
3192         else if (isOption(arg, "xs", "unpad-param-type"))
3193         {
3194                 formatter.setParamTypeUnPaddingMode(true);
3195         }
3196         else if (isOption(arg, "xM", "align-method-colon"))
3197         {
3198                 formatter.setAlignMethodColon(true);
3199         }
3200         else if ( isOption(arg, "xP0", "pad-method-colon=none") )
3201         {
3202                 formatter.setObjCColonPaddingMode(COLON_PAD_NONE);
3203         }
3204         else if ( isOption(arg, "xP1", "pad-method-colon=all") )
3205         {
3206                 formatter.setObjCColonPaddingMode(COLON_PAD_ALL);
3207         }
3208         else if ( isOption(arg, "xP2", "pad-method-colon=after") )
3209         {
3210                 formatter.setObjCColonPaddingMode(COLON_PAD_AFTER);
3211         }
3212         else if ( isOption(arg, "xP3", "pad-method-colon=before") )
3213         {
3214                 formatter.setObjCColonPaddingMode(COLON_PAD_BEFORE);
3215         }
3216         // depreciated options ////////////////////////////////////////////////////////////////////////
3217         else if ( isOption(arg, "indent-preprocessor") )                // depreciated release 2.04
3218         {
3219                 formatter.setPreprocDefineIndent(true);
3220         }
3221         else if ( isOption(arg, "style=ansi") )                                 // depreciated release 2.05
3222         {
3223                 formatter.setFormattingStyle(STYLE_ALLMAN);
3224         }
3225         // depreciated in release 3.0 /////////////////////////////////////////////////////////////////
3226         else if ( isOption(arg, "break-closing-brackets") )             // depreciated release 3.0
3227         {
3228                 formatter.setBreakClosingHeaderBracketsMode(true);
3229         }
3230         else if ( isOption(arg, "add-brackets") )                               // depreciated release 3.0
3231         {
3232                 formatter.setAddBracketsMode(true);
3233         }
3234         else if ( isOption(arg, "add-one-line-brackets") )              // depreciated release 3.0
3235         {
3236                 formatter.setAddOneLineBracketsMode(true);
3237         }
3238         else if ( isOption(arg, "remove-brackets") )                    // depreciated release 3.0
3239         {
3240                 formatter.setRemoveBracketsMode(true);
3241         }
3242         else if ( isParamOption(arg, "max-instatement-indent=") )       // depreciated release 3.0
3243         {
3244                 int maxIndent = 40;
3245                 string maxIndentParam = getParam(arg, "max-instatement-indent=");
3246                 if (maxIndentParam.length() > 0)
3247                         maxIndent = atoi(maxIndentParam.c_str());
3248                 if (maxIndent < 40)
3249                         isOptionError(arg, errorInfo);
3250                 else if (maxIndent > 120)
3251                         isOptionError(arg, errorInfo);
3252                 else
3253                         formatter.setMaxInStatementIndentLength(maxIndent);
3254         }
3255 //  NOTE: Removed in release 2.04.
3256 //      else if ( isOption(arg, "b", "brackets=break") )
3257 //      {
3258 //              formatter.setBracketFormatMode(BREAK_MODE);
3259 //      }
3260 //      else if ( isOption(arg, "a", "brackets=attach") )
3261 //      {
3262 //              formatter.setBracketFormatMode(ATTACH_MODE);
3263 //      }
3264 //      else if ( isOption(arg, "l", "brackets=linux") )
3265 //      {
3266 //              formatter.setBracketFormatMode(LINUX_MODE);
3267 //      }
3268 //      else if ( isOption(arg, "u", "brackets=stroustrup") )
3269 //      {
3270 //              formatter.setBracketFormatMode(STROUSTRUP_MODE);
3271 //      }
3272 //      else if ( isOption(arg, "g", "brackets=run-in") )
3273 //      {
3274 //              formatter.setBracketFormatMode(RUN_IN_MODE);
3275 //      }
3276         // end depreciated options ////////////////////////////////////////////////////////////////////
3277 #ifdef ASTYLE_LIB
3278         // End of options used by GUI /////////////////////////////////////////////////////////////////
3279         else
3280                 isOptionError(arg, errorInfo);
3281 #else
3282         // Options used by only console ///////////////////////////////////////////////////////////////
3283         else if ( isOption(arg, "n", "suffix=none") )
3284         {
3285                 console.setNoBackup(true);
3286         }
3287         else if ( isParamOption(arg, "suffix=") )
3288         {
3289                 string suffixParam = getParam(arg, "suffix=");
3290                 if (suffixParam.length() > 0)
3291                 {
3292                         console.setOrigSuffix(suffixParam);
3293                 }
3294         }
3295         else if ( isParamOption(arg, "exclude=") )
3296         {
3297                 string suffixParam = getParam(arg, "exclude=");
3298                 if (suffixParam.length() > 0)
3299                         console.updateExcludeVector(suffixParam);
3300         }
3301         else if ( isOption(arg, "r", "R") || isOption(arg, "recursive") )
3302         {
3303                 console.setIsRecursive(true);
3304         }
3305         else if (isOption(arg, "dry-run"))
3306         {
3307                 console.setIsDryRun(true);
3308         }
3309         else if ( isOption(arg, "Z", "preserve-date") )
3310         {
3311                 console.setPreserveDate(true);
3312         }
3313         else if ( isOption(arg, "v", "verbose") )
3314         {
3315                 console.setIsVerbose(true);
3316         }
3317         else if ( isOption(arg, "Q", "formatted") )
3318         {
3319                 console.setIsFormattedOnly(true);
3320         }
3321         else if ( isOption(arg, "q", "quiet") )
3322         {
3323                 console.setIsQuiet(true);
3324         }
3325         else if ( isOption(arg, "i", "ignore-exclude-errors") )
3326         {
3327                 console.setIgnoreExcludeErrors(true);
3328         }
3329         else if ( isOption(arg, "xi", "ignore-exclude-errors-x") )
3330         {
3331                 console.setIgnoreExcludeErrorsAndDisplay(true);
3332         }
3333         else if ( isOption(arg, "X", "errors-to-stdout") )
3334         {
3335                 console.setErrorStream(&cout);
3336         }
3337         else if ( isOption(arg, "lineend=windows") )
3338         {
3339                 formatter.setLineEndFormat(LINEEND_WINDOWS);
3340         }
3341         else if ( isOption(arg, "lineend=linux") )
3342         {
3343                 formatter.setLineEndFormat(LINEEND_LINUX);
3344         }
3345         else if ( isOption(arg, "lineend=macold") )
3346         {
3347                 formatter.setLineEndFormat(LINEEND_MACOLD);
3348         }
3349         else if ( isParamOption(arg, "z") )
3350         {
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);
3363         }
3364         else if ( isParamOption(arg, "stdin=") )
3365         {
3366                 string path = getParam(arg, "stdin=");
3367                 console.standardizePath(path);
3368                 console.setStdPathIn(path);
3369         }
3370         else if ( isParamOption(arg, "stdout=") )
3371         {
3372                 string path = getParam(arg, "stdout=");
3373                 console.standardizePath(path);
3374                 console.setStdPathOut(path);
3375         }
3376         else
3377                 isOptionError(arg, errorInfo);
3378 #endif
3379 }       // End of parseOption function
3380
3381 // Parse options from the options file.
3382 void ASOptions::importOptions(istream& in, vector<string>& optionsVector)
3383 {
3384         char ch;
3385         bool isInQuote = false;
3386         char quoteChar = ' ';
3387         string currentToken;
3388
3389         while (in)
3390         {
3391                 currentToken = "";
3392                 do
3393                 {
3394                         in.get(ch);
3395                         if (in.eof())
3396                                 break;
3397                         // treat '#' as line comments
3398                         if (ch == '#')
3399                                 while (in)
3400                                 {
3401                                         in.get(ch);
3402                                         if (ch == '\n' || ch == '\r')
3403                                                 break;
3404                                 }
3405
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 == ',')
3409                                 break;
3410                         if (ch == ' ' && !isInQuote)
3411                                 break;
3412                         if (ch == quoteChar && isInQuote)
3413                                 break;
3414                         if (ch == '"' || ch == '\'')
3415                         {
3416                                 isInQuote = true;
3417                                 quoteChar = ch;
3418                                 continue;
3419                         }
3420                         currentToken.append(1, ch);
3421                 }
3422                 while (in);
3423
3424                 if (currentToken.length() != 0)
3425                         optionsVector.emplace_back(currentToken);
3426                 isInQuote = false;
3427         }
3428 }
3429
3430 string ASOptions::getOptionErrors() const
3431 {
3432         return optionErrors.str();
3433 }
3434
3435 string ASOptions::getParam(const string& arg, const char* op)
3436 {
3437         return arg.substr(strlen(op));
3438 }
3439
3440 string ASOptions::getParam(const string& arg, const char* op1, const char* op2)
3441 {
3442         return isParamOption(arg, op1) ? getParam(arg, op1) : getParam(arg, op2);
3443 }
3444
3445 bool ASOptions::isOption(const string& arg, const char* op)
3446 {
3447         return arg.compare(op) == 0;
3448 }
3449
3450 bool ASOptions::isOption(const string& arg, const char* op1, const char* op2)
3451 {
3452         return (isOption(arg, op1) || isOption(arg, op2));
3453 }
3454
3455 void ASOptions::isOptionError(const string& arg, const string& errorInfo)
3456 {
3457         if (optionErrors.str().length() == 0)
3458                 optionErrors << errorInfo << endl;   // need main error message
3459         optionErrors << arg << endl;
3460 }
3461
3462 bool ASOptions::isParamOption(const string& arg, const char* option)
3463 {
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]))
3468                         retVal = false;
3469         return retVal;
3470 }
3471
3472 bool ASOptions::isParamOption(const string& arg, const char* option1, const char* option2)
3473 {
3474         return isParamOption(arg, option1) || isParamOption(arg, option2);
3475 }
3476
3477 //----------------------------------------------------------------------------
3478 // ASEncoding class
3479 //----------------------------------------------------------------------------
3480
3481 // Return true if an int is big endian.
3482 bool ASEncoding::getBigEndian() const
3483 {
3484         short int word = 0x0001;
3485         char* byte = (char*) &word;
3486         return (byte[0] ? false : true);
3487 }
3488
3489 // Swap the two low order bytes of a 16 bit integer value.
3490 int ASEncoding::swap16bit(int value) const
3491 {
3492         return ( ((value & 0xff) << 8) | ((value & 0xff00) >> 8) );
3493 }
3494
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
3498 {
3499         size_t length = 0;
3500         while (*utf16In++ != '\0')
3501                 length++;
3502         return length;
3503 }
3504
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
3511 {
3512         size_t len = 0;
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];)
3516         {
3517                 size_t uch = isBigEndian ? swap16bit(uptr[i]) : uptr[i];
3518                 if (uch < 0x80)
3519                         len++;
3520                 else if (uch < 0x800)
3521                         len += 2;
3522                 else if ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_TRAIL_LAST))
3523                 {
3524                         len += 4;
3525                         i++;
3526                 }
3527                 else
3528                         len += 3;
3529                 i++;
3530         }
3531         return len;
3532 }
3533
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
3539 {
3540         int nCur = 0;
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;
3546
3547         // the BOM will automatically be converted to utf-16
3548         while (pRead < pEnd)
3549         {
3550                 switch (state)
3551                 {
3552                         case eStart:
3553                                 if ((0xF0 & *pRead) == 0xF0)
3554                                 {
3555                                         nCur = (0x7 & *pRead) << 18;
3556                                         state = eSecondOf4Bytes;
3557                                 }
3558                                 else if ((0xE0 & *pRead) == 0xE0)
3559                                 {
3560                                         nCur = (~0xE0 & *pRead) << 12;
3561                                         state = ePenultimate;
3562                                 }
3563                                 else if ((0xC0 & *pRead) == 0xC0)
3564                                 {
3565                                         nCur = (~0xC0 & *pRead) << 6;
3566                                         state = eFinal;
3567                                 }
3568                                 else
3569                                 {
3570                                         nCur = *pRead;
3571                                         state = eStart;
3572                                 }
3573                                 break;
3574                         case eSecondOf4Bytes:
3575                                 nCur |= (0x3F & *pRead) << 12;
3576                                 state = ePenultimate;
3577                                 break;
3578                         case ePenultimate:
3579                                 nCur |= (0x3F & *pRead) << 6;
3580                                 state = eFinal;
3581                                 break;
3582                         case eFinal:
3583                                 nCur |= (0x3F & *pRead);
3584                                 state = eStart;
3585                                 break;
3586                                 // no default case is needed
3587                 }
3588                 ++pRead;
3589
3590                 if (state == eStart)
3591                 {
3592                         int codePoint = nCur;
3593                         if (codePoint >= SURROGATE_FIRST_VALUE)
3594                         {
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);
3600                         }
3601                         else
3602                                 *pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(codePoint) : codePoint);
3603                 }
3604         }
3605         // return value is the output length in BYTES (not wchar_t)
3606         return (pCur - pCurStart) * 2;
3607 }
3608
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
3615 {
3616         size_t ulen = 0;
3617         size_t charLen;
3618         for (size_t i = 0; i < len;)
3619         {
3620                 unsigned char ch = static_cast<unsigned char>(utf8In[i]);
3621                 if (ch < 0x80)
3622                         charLen = 1;
3623                 else if (ch < 0x80 + 0x40 + 0x20)
3624                         charLen = 2;
3625                 else if (ch < 0x80 + 0x40 + 0x20 + 0x10)
3626                         charLen = 3;
3627                 else
3628                 {
3629                         charLen = 4;
3630                         ulen++;
3631                 }
3632                 i += charLen;
3633                 ulen++;
3634         }
3635         // return value is the length in bytes (not wchar_t)
3636         return ulen * 2;
3637 }
3638
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
3645 {
3646         int nCur16 = 0;
3647         int nCur = 0;
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
3653         if (firstBlock)
3654                 state = eStart;
3655
3656         // the BOM will automatically be converted to utf-8
3657         while (pRead < pEnd)
3658         {
3659                 switch (state)
3660                 {
3661                         case eStart:
3662                                 if (pRead >= pEnd)
3663                                 {
3664                                         ++pRead;
3665                                         break;
3666                                 }
3667                                 if (isBigEndian)
3668                                 {
3669                                         nCur16 = static_cast<utf16>(*pRead++ << 8);
3670                                         nCur16 |= static_cast<utf16>(*pRead);
3671                                 }
3672                                 else
3673                                 {
3674                                         nCur16 = *pRead++;
3675                                         nCur16 |= static_cast<utf16>(*pRead << 8);
3676                                 }
3677                                 if (nCur16 >= SURROGATE_LEAD_FIRST && nCur16 <= SURROGATE_LEAD_LAST)
3678                                 {
3679                                         ++pRead;
3680                                         int trail;
3681                                         if (isBigEndian)
3682                                         {
3683                                                 trail = static_cast<utf16>(*pRead++ << 8);
3684                                                 trail |= static_cast<utf16>(*pRead);
3685                                         }
3686                                         else
3687                                         {
3688                                                 trail = *pRead++;
3689                                                 trail |= static_cast<utf16>(*pRead << 8);
3690                                         }
3691                                         nCur16 = (((nCur16 & 0x3ff) << 10) | (trail & 0x3ff)) + SURROGATE_FIRST_VALUE;
3692                                 }
3693                                 ++pRead;
3694
3695                                 if (nCur16 < 0x80)
3696                                 {
3697                                         nCur = static_cast<ubyte>(nCur16 & 0xFF);
3698                                         state = eStart;
3699                                 }
3700                                 else if (nCur16 < 0x800)
3701                                 {
3702                                         nCur = static_cast<ubyte>(0xC0 | (nCur16 >> 6));
3703                                         state = eFinal;
3704                                 }
3705                                 else if (nCur16 < SURROGATE_FIRST_VALUE)
3706                                 {
3707                                         nCur = static_cast<ubyte>(0xE0 | (nCur16 >> 12));
3708                                         state = ePenultimate;
3709                                 }
3710                                 else
3711                                 {
3712                                         nCur = static_cast<ubyte>(0xF0 | (nCur16 >> 18));
3713                                         state = eSecondOf4Bytes;
3714                                 }
3715                                 break;
3716                         case eSecondOf4Bytes:
3717                                 nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 12) & 0x3F));
3718                                 state = ePenultimate;
3719                                 break;
3720                         case ePenultimate:
3721                                 nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 6) & 0x3F));
3722                                 state = eFinal;
3723                                 break;
3724                         case eFinal:
3725                                 nCur = static_cast<ubyte>(0x80 | (nCur16 & 0x3F));
3726                                 state = eStart;
3727                                 break;
3728                                 // no default case is needed
3729                 }
3730                 *pCur++ = static_cast<ubyte>(nCur);
3731         }
3732         return pCur - pCurStart;
3733 }
3734
3735 //----------------------------------------------------------------------------
3736
3737 }   // namespace astyle
3738
3739 //----------------------------------------------------------------------------
3740
3741 using namespace astyle;
3742
3743 //----------------------------------------------------------------------------
3744 // ASTYLE_JNI functions for Java library builds
3745 //----------------------------------------------------------------------------
3746
3747 #ifdef ASTYLE_JNI
3748
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
3751 extern "C"  EXPORT
3752 jstring STDCALL Java_AStyleInterface_AStyleGetVersion(JNIEnv* env, jclass)
3753 {
3754         return env->NewStringUTF(g_version);
3755 }
3756
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
3759 extern "C"  EXPORT
3760 jstring STDCALL Java_AStyleInterface_AStyleMain(JNIEnv* env,
3761                                                 jobject obj,
3762                                                 jstring textInJava,
3763                                                 jstring optionsJava)
3764 {
3765         g_env = env;                                // make object available globally
3766         g_obj = obj;                                // make object available globally
3767
3768         jstring textErr = env->NewStringUTF("");    // zero length text returned if an error occurs
3769
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)
3774         {
3775                 cout << "Cannot find java method ErrorHandler" << endl;
3776                 return textErr;
3777         }
3778
3779         // convert jstring to char*
3780         const char* textIn = env->GetStringUTFChars(textInJava, nullptr);
3781         const char* options = env->GetStringUTFChars(optionsJava, nullptr);
3782
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)
3787                 return textErr;
3788
3789         // release memory
3790         jstring textOutJava = env->NewStringUTF(textOut);
3791         delete[] textOut;
3792         env->ReleaseStringUTFChars(textInJava, textIn);
3793         env->ReleaseStringUTFChars(optionsJava, options);
3794
3795         return textOutJava;
3796 }
3797
3798 // Call the Java error handler
3799 void STDCALL javaErrorHandler(int errorNumber, const char* errorMessage)
3800 {
3801         jstring errorMessageJava = g_env->NewStringUTF(errorMessage);
3802         g_env->CallVoidMethod(g_obj, g_mid, errorNumber, errorMessageJava);
3803 }
3804
3805 // Allocate memory for the formatted text
3806 char* STDCALL javaMemoryAlloc(unsigned long memoryNeeded)
3807 {
3808         // error condition is checked after return from AStyleMain
3809         char* buffer = new (nothrow) char[memoryNeeded];
3810         return buffer;
3811 }
3812
3813 #endif  // ASTYLE_JNI
3814
3815 //----------------------------------------------------------------------------
3816 // ASTYLE_LIB functions for library builds
3817 //----------------------------------------------------------------------------
3818
3819 #ifdef ASTYLE_LIB
3820
3821 //----------------------------------------------------------------------------
3822 // ASTYLE_LIB entry point for AStyleMainUtf16 library builds
3823 //----------------------------------------------------------------------------
3824 /*
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
3830 */
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
3835 {
3836         if (fpErrorHandler == nullptr)         // cannot display a message if no error handler
3837                 return nullptr;
3838
3839         if (pSourceIn == nullptr)
3840         {
3841                 fpErrorHandler(101, "No pointer to source input.");
3842                 return nullptr;
3843         }
3844         if (pOptions == nullptr)
3845         {
3846                 fpErrorHandler(102, "No pointer to AStyle options.");
3847                 return nullptr;
3848         }
3849         if (fpMemoryAlloc == nullptr)
3850         {
3851                 fpErrorHandler(103, "No pointer to memory allocation function.");
3852                 return nullptr;
3853         }
3854 #ifndef _WIN32
3855         // check size of utf16_t on Linux
3856         int sizeCheck = 2;
3857         if (sizeof(utf16_t) != sizeCheck)
3858         {
3859                 fpErrorHandler(104, "Unsigned short is not the correct size.");
3860                 return nullptr;
3861         }
3862 #endif
3863
3864         ASLibrary library;
3865         utf16_t* utf16Out = library.formatUtf16(pSourceIn, pOptions, fpErrorHandler, fpMemoryAlloc);
3866         return utf16Out;
3867 }
3868
3869 //----------------------------------------------------------------------------
3870 // ASTYLE_LIB entry point for library builds
3871 //----------------------------------------------------------------------------
3872 /*
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
3878  */
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
3883 {
3884         if (fpErrorHandler == nullptr)         // cannot display a message if no error handler
3885                 return nullptr;
3886
3887         if (pSourceIn == nullptr)
3888         {
3889                 fpErrorHandler(101, "No pointer to source input.");
3890                 return nullptr;
3891         }
3892         if (pOptions == nullptr)
3893         {
3894                 fpErrorHandler(102, "No pointer to AStyle options.");
3895                 return nullptr;
3896         }
3897         if (fpMemoryAlloc == nullptr)
3898         {
3899                 fpErrorHandler(103, "No pointer to memory allocation function.");
3900                 return nullptr;
3901         }
3902
3903         ASFormatter formatter;
3904         ASOptions options(formatter);
3905
3906         vector<string> optionsVector;
3907         istringstream opt(pOptions);
3908
3909         options.importOptions(opt, optionsVector);
3910
3911         bool ok = options.parseOptions(optionsVector, "Invalid Artistic Style options:");
3912         if (!ok)
3913                 fpErrorHandler(130, options.getOptionErrors().c_str());
3914
3915         istringstream in(pSourceIn);
3916         ASStreamIterator<istringstream> streamIterator(&in);
3917         ostringstream out;
3918         formatter.init(&streamIterator);
3919
3920         while (formatter.hasMoreLines())
3921         {
3922                 out << formatter.nextLine();
3923                 if (formatter.hasMoreLines())
3924                         out << streamIterator.getOutputEOL();
3925                 else
3926                 {
3927                         // this can happen if the file if missing a closing brace and break-blocks is requested
3928                         if (formatter.getIsLineReady())
3929                         {
3930                                 out << streamIterator.getOutputEOL();
3931                                 out << formatter.nextLine();
3932                         }
3933                 }
3934         }
3935
3936         size_t textSizeOut = out.str().length();
3937         char* pTextOut = fpMemoryAlloc((long)textSizeOut + 1);     // call memory allocation function
3938         if (pTextOut == nullptr)
3939         {
3940                 fpErrorHandler(120, "Allocation failure on output.");
3941                 return nullptr;
3942         }
3943
3944         strcpy(pTextOut, out.str().c_str());
3945 #ifndef NDEBUG
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)
3950                 fpErrorHandler(220,
3951                                "Checksum error.\n"
3952                                "The incorrectly formatted file will be returned for debugging.");
3953 #endif
3954         return pTextOut;
3955 }
3956
3957 extern "C" EXPORT const char* STDCALL AStyleGetVersion(void)
3958 {
3959         return g_version;
3960 }
3961
3962 // ASTYLECON_LIB is defined to exclude "main" from the test programs
3963 #elif !defined(ASTYLECON_LIB)
3964
3965 //----------------------------------------------------------------------------
3966 // main function for ASConsole build
3967 //----------------------------------------------------------------------------
3968
3969 int main(int argc, char** argv)
3970 {
3971         // create objects
3972         ASFormatter formatter;
3973         auto console = make_shared<ASConsole>(formatter);
3974
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);
3980
3981         // if no files have been given, use cin for input and cout for output
3982         if (!console->fileNameVectorIsEmpty())
3983                 console->processFiles();
3984         else
3985                 console->formatCinToCout();
3986
3987         return EXIT_SUCCESS;
3988 }
3989
3990 #endif  // ASTYLE_LIB