1 // astyle_main.cpp
2 // Copyright (c) 2018 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.1";
98 
99 //-----------------------------------------------------------------------------
100 // ASStreamIterator class
101 // typename will be stringstream for AStyle
102 // it could be istream or wxChar for plug-ins
103 //-----------------------------------------------------------------------------
104 
105 template<typename T>
ASStreamIterator(T * in)106 ASStreamIterator<T>::ASStreamIterator(T* in)
107 {
108 	inStream = in;
109 	buffer.reserve(200);
110 	eolWindows = 0;
111 	eolLinux = 0;
112 	eolMacOld = 0;
113 	peekStart = 0;
114 	prevLineDeleted = false;
115 	checkForEmptyLine = false;
116 	// get length of stream
117 	inStream->seekg(0, inStream->end);
118 	streamLength = inStream->tellg();
119 	inStream->seekg(0, inStream->beg);
120 }
121 
122 template<typename T>
~ASStreamIterator()123 ASStreamIterator<T>::~ASStreamIterator()
124 {
125 }
126 
127 /**
128 * get the length of the input stream.
129 * streamLength variable is set by the constructor.
130 *
131 * @return     length of the input file stream, converted to an int.
132 */
133 template<typename T>
getStreamLength() const134 int ASStreamIterator<T>::getStreamLength() const
135 {
136 	return static_cast<int>(streamLength);
137 }
138 
139 /**
140  * read the input stream, delete any end of line characters,
141  *     and build a string that contains the input line.
142  *
143  * @return        string containing the next input line minus any end of line characters
144  */
145 template<typename T>
nextLine(bool emptyLineWasDeleted)146 string ASStreamIterator<T>::nextLine(bool emptyLineWasDeleted)
147 {
148 	// verify that the current position is correct
149 	assert(peekStart == 0);
150 
151 	// a deleted line may be replaced if break-blocks is requested
152 	// this sets up the compare to check for a replaced empty line
153 	if (prevLineDeleted)
154 	{
155 		prevLineDeleted = false;
156 		checkForEmptyLine = true;
157 	}
158 	if (!emptyLineWasDeleted)
159 		prevBuffer = buffer;
160 	else
161 		prevLineDeleted = true;
162 
163 	// read the next record
164 	buffer.clear();
165 	char ch;
166 	inStream->get(ch);
167 
168 	while (!inStream->eof() && ch != '\n' && ch != '\r')
169 	{
170 		buffer.append(1, ch);
171 		inStream->get(ch);
172 	}
173 
174 	if (inStream->eof())
175 	{
176 		return buffer;
177 	}
178 
179 	int peekCh = inStream->peek();
180 
181 	// find input end-of-line characters
182 	if (!inStream->eof())
183 	{
184 		if (ch == '\r')         // CR+LF is windows otherwise Mac OS 9
185 		{
186 			if (peekCh == '\n')
187 			{
188 				inStream->get();
189 				eolWindows++;
190 			}
191 			else
192 				eolMacOld++;
193 		}
194 		else                    // LF is Linux, allow for improbable LF/CR
195 		{
196 			if (peekCh == '\r')
197 			{
198 				inStream->get();
199 				eolWindows++;
200 			}
201 			else
202 				eolLinux++;
203 		}
204 	}
205 	else
206 	{
207 		inStream->clear();
208 	}
209 
210 	// has not detected an input end of line
211 	if (!eolWindows && !eolLinux && !eolMacOld)
212 	{
213 #ifdef _WIN32
214 		eolWindows++;
215 #else
216 		eolLinux++;
217 #endif
218 	}
219 
220 	// set output end of line characters
221 	if (eolWindows >= eolLinux)
222 	{
223 		if (eolWindows >= eolMacOld)
224 			outputEOL = "\r\n";     // Windows (CR+LF)
225 		else
226 			outputEOL = "\r";       // MacOld (CR)
227 	}
228 	else if (eolLinux >= eolMacOld)
229 		outputEOL = "\n";           // Linux (LF)
230 	else
231 		outputEOL = "\r";           // MacOld (CR)
232 
233 	return buffer;
234 }
235 
236 // save the current position and get the next line
237 // this can be called for multiple reads
238 // when finished peeking you MUST call peekReset()
239 // call this function from ASFormatter ONLY
240 template<typename T>
peekNextLine()241 string ASStreamIterator<T>::peekNextLine()
242 {
243 	assert(hasMoreLines());
244 	string nextLine_;
245 	char ch;
246 
247 	if (peekStart == 0)
248 		peekStart = inStream->tellg();
249 
250 	// read the next record
251 	inStream->get(ch);
252 	while (!inStream->eof() && ch != '\n' && ch != '\r')
253 	{
254 		nextLine_.append(1, ch);
255 		inStream->get(ch);
256 	}
257 
258 	if (inStream->eof())
259 	{
260 		return nextLine_;
261 	}
262 
263 	int peekCh = inStream->peek();
264 
265 	// remove end-of-line characters
266 	if (!inStream->eof())
267 	{
268 		if ((peekCh == '\n' || peekCh == '\r') && peekCh != ch)
269 			inStream->get();
270 	}
271 
272 	return nextLine_;
273 }
274 
275 // reset current position and EOF for peekNextLine()
276 template<typename T>
peekReset()277 void ASStreamIterator<T>::peekReset()
278 {
279 	assert(peekStart != 0);
280 	inStream->clear();
281 	inStream->seekg(peekStart);
282 	peekStart = 0;
283 }
284 
285 // save the last input line after input has reached EOF
286 template<typename T>
saveLastInputLine()287 void ASStreamIterator<T>::saveLastInputLine()
288 {
289 	assert(inStream->eof());
290 	prevBuffer = buffer;
291 }
292 
293 // return position of the get pointer
294 template<typename T>
tellg()295 streamoff ASStreamIterator<T>::tellg()
296 {
297 	return inStream->tellg();
298 }
299 
300 // check for a change in line ends
301 template<typename T>
getLineEndChange(int lineEndFormat) const302 bool ASStreamIterator<T>::getLineEndChange(int lineEndFormat) const
303 {
304 	assert(lineEndFormat == LINEEND_DEFAULT
305 	       || lineEndFormat == LINEEND_WINDOWS
306 	       || lineEndFormat == LINEEND_LINUX
307 	       || lineEndFormat == LINEEND_MACOLD);
308 
309 	bool lineEndChange = false;
310 	if (lineEndFormat == LINEEND_WINDOWS)
311 		lineEndChange = (eolLinux + eolMacOld != 0);
312 	else if (lineEndFormat == LINEEND_LINUX)
313 		lineEndChange = (eolWindows + eolMacOld != 0);
314 	else if (lineEndFormat == LINEEND_MACOLD)
315 		lineEndChange = (eolWindows + eolLinux != 0);
316 	else
317 	{
318 		if (eolWindows > 0)
319 			lineEndChange = (eolLinux + eolMacOld != 0);
320 		else if (eolLinux > 0)
321 			lineEndChange = (eolWindows + eolMacOld != 0);
322 		else if (eolMacOld > 0)
323 			lineEndChange = (eolWindows + eolLinux != 0);
324 	}
325 	return lineEndChange;
326 }
327 
328 //-----------------------------------------------------------------------------
329 // ASConsole class
330 // main function will be included only in the console build
331 //-----------------------------------------------------------------------------
332 
333 #ifndef ASTYLE_LIB
334 
ASConsole(ASFormatter & formatterArg)335 ASConsole::ASConsole(ASFormatter& formatterArg) : formatter(formatterArg)
336 {
337 	errorStream = &cerr;
338 	// command line options
339 	isRecursive = false;
340 	isDryRun = false;
341 	noBackup = false;
342 	preserveDate = false;
343 	isVerbose = false;
344 	isQuiet = false;
345 	isFormattedOnly = false;
346 	ignoreExcludeErrors = false;
347 	ignoreExcludeErrorsDisplay = false;
348 	useAscii = false;
349 	// other variables
350 	bypassBrowserOpen = false;
351 	hasWildcard = false;
352 	filesAreIdentical = true;
353 	lineEndsMixed = false;
354 	origSuffix = ".orig";
355 	mainDirectoryLength = 0;
356 	filesFormatted = 0;
357 	filesUnchanged = 0;
358 	linesOut = 0;
359 }
360 
~ASConsole()361 ASConsole::~ASConsole()
362 {}
363 
364 // rewrite a stringstream converting the line ends
convertLineEnds(ostringstream & out,int lineEnd)365 void ASConsole::convertLineEnds(ostringstream& out, int lineEnd)
366 {
367 	assert(lineEnd == LINEEND_WINDOWS || lineEnd == LINEEND_LINUX || lineEnd == LINEEND_MACOLD);
368 	const string& inStr = out.str();	// avoids strange looking syntax
369 	string outStr;						// the converted output
370 	int inLength = (int) inStr.length();
371 	for (int pos = 0; pos < inLength; pos++)
372 	{
373 		if (inStr[pos] == '\r')
374 		{
375 			if (inStr[pos + 1] == '\n')
376 			{
377 				// CRLF
378 				if (lineEnd == LINEEND_CR)
379 				{
380 					outStr += inStr[pos];		// Delete the LF
381 					pos++;
382 					continue;
383 				}
384 				else if (lineEnd == LINEEND_LF)
385 				{
386 					outStr += inStr[pos + 1];		// Delete the CR
387 					pos++;
388 					continue;
389 				}
390 				else
391 				{
392 					outStr += inStr[pos];		// Do not change
393 					outStr += inStr[pos + 1];
394 					pos++;
395 					continue;
396 				}
397 			}
398 			else
399 			{
400 				// CR
401 				if (lineEnd == LINEEND_CRLF)
402 				{
403 					outStr += inStr[pos];		// Insert the CR
404 					outStr += '\n';				// Insert the LF
405 					continue;
406 				}
407 				else if (lineEnd == LINEEND_LF)
408 				{
409 					outStr += '\n';				// Insert the LF
410 					continue;
411 				}
412 				else
413 				{
414 					outStr += inStr[pos];		// Do not change
415 					continue;
416 				}
417 			}
418 		}
419 		else if (inStr[pos] == '\n')
420 		{
421 			// LF
422 			if (lineEnd == LINEEND_CRLF)
423 			{
424 				outStr += '\r';				// Insert the CR
425 				outStr += inStr[pos];		// Insert the LF
426 				continue;
427 			}
428 			else if (lineEnd == LINEEND_CR)
429 			{
430 				outStr += '\r';				// Insert the CR
431 				continue;
432 			}
433 			else
434 			{
435 				outStr += inStr[pos];		// Do not change
436 				continue;
437 			}
438 		}
439 		else
440 		{
441 			outStr += inStr[pos];		// Write the current char
442 		}
443 	}
444 	// replace the stream
445 	out.str(outStr);
446 }
447 
correctMixedLineEnds(ostringstream & out)448 void ASConsole::correctMixedLineEnds(ostringstream& out)
449 {
450 	LineEndFormat lineEndFormat = LINEEND_DEFAULT;
451 	if (outputEOL == "\r\n")
452 		lineEndFormat = LINEEND_WINDOWS;
453 	if (outputEOL == "\n")
454 		lineEndFormat = LINEEND_LINUX;
455 	if (outputEOL == "\r")
456 		lineEndFormat = LINEEND_MACOLD;
457 	convertLineEnds(out, lineEndFormat);
458 }
459 
460 // check files for 16 or 32 bit encoding
461 // the file must have a Byte Order Mark (BOM)
462 // NOTE: some string functions don't work with NULLs (e.g. length())
detectEncoding(const char * data,size_t dataSize) const463 FileEncoding ASConsole::detectEncoding(const char* data, size_t dataSize) const
464 {
465 	FileEncoding encoding = ENCODING_8BIT;
466 
467 	if (dataSize >= 3 && memcmp(data, "\xEF\xBB\xBF", 3) == 0)
468 		encoding = UTF_8BOM;
469 	else if (dataSize >= 4 && memcmp(data, "\x00\x00\xFE\xFF", 4) == 0)
470 		encoding = UTF_32BE;
471 	else if (dataSize >= 4 && memcmp(data, "\xFF\xFE\x00\x00", 4) == 0)
472 		encoding = UTF_32LE;
473 	else if (dataSize >= 2 && memcmp(data, "\xFE\xFF", 2) == 0)
474 		encoding = UTF_16BE;
475 	else if (dataSize >= 2 && memcmp(data, "\xFF\xFE", 2) == 0)
476 		encoding = UTF_16LE;
477 
478 	return encoding;
479 }
480 
481 // error exit without a message
error() const482 void ASConsole::error() const
483 {
484 	(*errorStream) << _("Artistic Style has terminated\n") << endl;
485 	exit(EXIT_FAILURE);
486 }
487 
488 // error exit with a message
error(const char * why,const char * what) const489 void ASConsole::error(const char* why, const char* what) const
490 {
491 	(*errorStream) << why << ' ' << what << endl;
492 	error();
493 }
494 
495 /**
496  * If no files have been given, use cin for input and cout for output.
497  *
498  * This is used to format text for text editors.
499  * Do NOT display any console messages when this function is used.
500  */
formatCinToCout()501 void ASConsole::formatCinToCout()
502 {
503 	// check for files from --stdin= and --stdout=
504 	if (!stdPathIn.empty())
505 	{
506 		if (!freopen(stdPathIn.c_str(), "r", stdin))
507 			error("Cannot open input file", stdPathIn.c_str());
508 	}
509 	if (!stdPathOut.empty())
510 	{
511 		if (!freopen(stdPathOut.c_str(), "w", stdout))
512 			error("Cannot open output file", stdPathOut.c_str());
513 
514 	}
515 	// Using cin.tellg() causes problems with both Windows and Linux.
516 	// The Windows problem occurs when the input is not Windows line-ends.
517 	// The tellg() will be out of sequence with the get() statements.
518 	// The Linux cin.tellg() will return -1 (invalid).
519 	// Copying the input sequentially to a stringstream before
520 	// formatting solves the problem for both.
521 	istream* inStream = &cin;
522 	stringstream outStream;
523 	char ch;
524 	inStream->get(ch);
525 	while (!inStream->eof() && !inStream->fail())
526 	{
527 		outStream.put(ch);
528 		inStream->get(ch);
529 	}
530 	ASStreamIterator<stringstream> streamIterator(&outStream);
531 	// Windows pipe or redirection always outputs Windows line-ends.
532 	// Linux pipe or redirection will output any line end.
533 #ifdef _WIN32
534 	LineEndFormat lineEndFormat = LINEEND_DEFAULT;
535 #else
536 	LineEndFormat lineEndFormat = formatter.getLineEndFormat();
537 #endif // _WIN32
538 	initializeOutputEOL(lineEndFormat);
539 	formatter.init(&streamIterator);
540 
541 	while (formatter.hasMoreLines())
542 	{
543 		cout << formatter.nextLine();
544 		if (formatter.hasMoreLines())
545 		{
546 			setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
547 			cout << outputEOL;
548 		}
549 		else
550 		{
551 			// this can happen if the file if missing a closing brace and break-blocks is requested
552 			if (formatter.getIsLineReady())
553 			{
554 				setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
555 				cout << outputEOL;
556 				cout << formatter.nextLine();
557 			}
558 		}
559 	}
560 	cout.flush();
561 }
562 
563 /**
564  * Open input file, format it, and close the output.
565  *
566  * @param fileName_     The path and name of the file to be processed.
567  */
formatFile(const string & fileName_)568 void ASConsole::formatFile(const string& fileName_)
569 {
570 	stringstream in;
571 	ostringstream out;
572 	FileEncoding encoding = readFile(fileName_, in);
573 
574 	// Unless a specific language mode has been set, set the language mode
575 	// according to the file's suffix.
576 	if (!formatter.getModeManuallySet())
577 	{
578 		if (stringEndsWith(fileName_, string(".java")))
579 			formatter.setJavaStyle();
580 		else if (stringEndsWith(fileName_, string(".cs")))
581 			formatter.setSharpStyle();
582 		else
583 			formatter.setCStyle();
584 	}
585 
586 	// set line end format
587 	string nextLine;				// next output line
588 	filesAreIdentical = true;		// input and output files are identical
589 	LineEndFormat lineEndFormat = formatter.getLineEndFormat();
590 	initializeOutputEOL(lineEndFormat);
591 	// do this AFTER setting the file mode
592 	ASStreamIterator<stringstream> streamIterator(&in);
593 	formatter.init(&streamIterator);
594 
595 	// format the file
596 	while (formatter.hasMoreLines())
597 	{
598 		nextLine = formatter.nextLine();
599 		out << nextLine;
600 		linesOut++;
601 		if (formatter.hasMoreLines())
602 		{
603 			setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
604 			out << outputEOL;
605 		}
606 		else
607 		{
608 			streamIterator.saveLastInputLine();     // to compare the last input line
609 			// this can happen if the file if missing a closing brace and break-blocks is requested
610 			if (formatter.getIsLineReady())
611 			{
612 				setOutputEOL(lineEndFormat, streamIterator.getOutputEOL());
613 				out << outputEOL;
614 				nextLine = formatter.nextLine();
615 				out << nextLine;
616 				linesOut++;
617 				streamIterator.saveLastInputLine();
618 			}
619 		}
620 
621 		if (filesAreIdentical)
622 		{
623 			if (streamIterator.checkForEmptyLine)
624 			{
625 				if (nextLine.find_first_not_of(" \t") != string::npos)
626 					filesAreIdentical = false;
627 			}
628 			else if (!streamIterator.compareToInputBuffer(nextLine))
629 				filesAreIdentical = false;
630 			streamIterator.checkForEmptyLine = false;
631 		}
632 	}
633 	// correct for mixed line ends
634 	if (lineEndsMixed)
635 	{
636 		correctMixedLineEnds(out);
637 		filesAreIdentical = false;
638 	}
639 
640 	// remove targetDirectory from filename if required by print
641 	string displayName;
642 	if (hasWildcard)
643 		displayName = fileName_.substr(targetDirectory.length() + 1);
644 	else
645 		displayName = fileName_;
646 
647 	// if file has changed, write the new file
648 	if (!filesAreIdentical || streamIterator.getLineEndChange(lineEndFormat))
649 	{
650 		if (!isDryRun)
651 			writeFile(fileName_, encoding, out);
652 		printMsg(_("Formatted  %s\n"), displayName);
653 		filesFormatted++;
654 	}
655 	else
656 	{
657 		if (!isFormattedOnly)
658 			printMsg(_("Unchanged  %s\n"), displayName);
659 		filesUnchanged++;
660 	}
661 
662 	assert(formatter.getChecksumDiff() == 0);
663 }
664 
665 /**
666  * Searches for a file named fileName_ in the current directory. If it is not
667  * found, recursively searches for fileName_ in the current directory's parent
668  * directories, returning the location of the first instance of fileName_
669  * found. If fileName_ is not found, an empty string is returned.
670  *
671  * @param fileName_     The filename the function should attempt to locate.
672  * @return              The full path to fileName_ in the current directory or
673  *                      nearest parent directory if found, otherwise an empty
674  *                      string.
675  */
findProjectOptionFilePath(const string & fileName_) const676 string ASConsole::findProjectOptionFilePath(const string& fileName_) const
677 {
678 	string parent;
679 
680 	if (!fileNameVector.empty())
681 		parent = getFullPathName(fileNameVector.front());
682 	else if (!stdPathIn.empty())
683 		parent = getFullPathName(stdPathIn);
684 	else
685 		parent = getFullPathName(getCurrentDirectory(fileName_));
686 
687 	// remove filename from path
688 	size_t endPath = parent.find_last_of(g_fileSeparator);
689 	if (endPath != string::npos)
690 		parent = parent.substr(0, endPath + 1);
691 
692 	while (!parent.empty())
693 	{
694 		string filepath = parent + fileName_;
695 		if (fileExists(filepath.c_str()))
696 			return filepath;
697 		else if (fileName_ == ".astylerc")
698 		{
699 			filepath = parent + "_astylerc";
700 			if (fileExists(filepath.c_str()))
701 				return filepath;
702 		}
703 		parent = getParentDirectory(parent);
704 	}
705 	return string();
706 }
707 
708 // for unit testing
getExcludeHitsVector() const709 vector<bool> ASConsole::getExcludeHitsVector() const
710 { return excludeHitsVector; }
711 
712 // for unit testing
getExcludeVector() const713 vector<string> ASConsole::getExcludeVector() const
714 { return excludeVector; }
715 
716 // for unit testing
getFileName() const717 vector<string> ASConsole::getFileName() const
718 { return fileName; }
719 
720 // for unit testing
getFileNameVector() const721 vector<string> ASConsole::getFileNameVector() const
722 { return fileNameVector; }
723 
724 // for unit testing
getFileOptionsVector() const725 vector<string> ASConsole::getFileOptionsVector() const
726 { return fileOptionsVector; }
727 
728 // for unit testing
getFilesAreIdentical() const729 bool ASConsole::getFilesAreIdentical() const
730 { return filesAreIdentical; }
731 
732 // for unit testing
getFilesFormatted() const733 int ASConsole::getFilesFormatted() const
734 { return filesFormatted; }
735 
736 // for unit testing
getIgnoreExcludeErrors() const737 bool ASConsole::getIgnoreExcludeErrors() const
738 { return ignoreExcludeErrors; }
739 
740 // for unit testing
getIgnoreExcludeErrorsDisplay() const741 bool ASConsole::getIgnoreExcludeErrorsDisplay() const
742 { return ignoreExcludeErrorsDisplay; }
743 
744 // for unit testing
getIsDryRun() const745 bool ASConsole::getIsDryRun() const
746 { return isDryRun; }
747 
748 // for unit testing
getIsFormattedOnly() const749 bool ASConsole::getIsFormattedOnly() const
750 { return isFormattedOnly; }
751 
752 // for unit testing
getLanguageID() const753 string ASConsole::getLanguageID() const
754 { return localizer.getLanguageID(); }
755 
756 // for unit testing
getIsQuiet() const757 bool ASConsole::getIsQuiet() const
758 { return isQuiet; }
759 
760 // for unit testing
getIsRecursive() const761 bool ASConsole::getIsRecursive() const
762 { return isRecursive; }
763 
764 // for unit testing
getIsVerbose() const765 bool ASConsole::getIsVerbose() const
766 { return isVerbose; }
767 
768 // for unit testing
getLineEndsMixed() const769 bool ASConsole::getLineEndsMixed() const
770 { return lineEndsMixed; }
771 
772 // for unit testing
getNoBackup() const773 bool ASConsole::getNoBackup() const
774 { return noBackup; }
775 
776 // for unit testing
getOptionFileName() const777 string ASConsole::getOptionFileName() const
778 { return optionFileName; }
779 
780 // for unit testing
getOptionsVector() const781 vector<string> ASConsole::getOptionsVector() const
782 { return optionsVector; }
783 
784 // for unit testing
getOrigSuffix() const785 string ASConsole::getOrigSuffix() const
786 { return origSuffix; }
787 
788 // for unit testing
getPreserveDate() const789 bool ASConsole::getPreserveDate() const
790 { return preserveDate; }
791 
792 // for unit testing
getProjectOptionFileName() const793 string ASConsole::getProjectOptionFileName() const
794 {
795 	assert(projectOptionFileName.length() > 0);
796 	// remove the directory path
797 	size_t start = projectOptionFileName.find_last_of(g_fileSeparator);
798 	if (start == string::npos)
799 		start = 0;
800 	return projectOptionFileName.substr(start + 1);
801 }
802 
803 // for unit testing
getProjectOptionsVector() const804 vector<string> ASConsole::getProjectOptionsVector() const
805 { return projectOptionsVector; }
806 
807 // for unit testing
getStdPathIn() const808 string ASConsole::getStdPathIn() const
809 { return stdPathIn; }
810 
811 // for unit testing
getStdPathOut() const812 string ASConsole::getStdPathOut() const
813 { return stdPathOut; }
814 
815 // for unit testing
setBypassBrowserOpen(bool state)816 void ASConsole::setBypassBrowserOpen(bool state)
817 { bypassBrowserOpen = state; }
818 
819 // for unit testing
getErrorStream() const820 ostream* ASConsole::getErrorStream() const
821 {
822 	return errorStream;
823 }
824 
setErrorStream(ostream * errStreamPtr)825 void ASConsole::setErrorStream(ostream* errStreamPtr)
826 {
827 	errorStream = errStreamPtr;
828 }
829 
830 // build a vector of argv options
831 // the program path argv[0] is excluded
getArgvOptions(int argc,char ** argv) const832 vector<string> ASConsole::getArgvOptions(int argc, char** argv) const
833 {
834 	vector<string> argvOptions;
835 	for (int i = 1; i < argc; i++)
836 	{
837 		argvOptions.emplace_back(string(argv[i]));
838 	}
839 	return argvOptions;
840 }
841 
getParam(const string & arg,const char * op)842 string ASConsole::getParam(const string& arg, const char* op)
843 {
844 	return arg.substr(strlen(op));
845 }
846 
getTargetFilenames(string & targetFilename_,vector<string> & targetFilenameVector) const847 void ASConsole::getTargetFilenames(string& targetFilename_,
848                                    vector<string>& targetFilenameVector) const
849 {
850 	size_t beg = 0;
851 	size_t sep = 0;
852 	while (beg < targetFilename_.length())
853 	{
854 		// find next target
855 		sep = targetFilename_.find_first_of(",;", beg);
856 		if (sep == string::npos)
857 			sep = targetFilename_.length();
858 		string fileExtension = targetFilename_.substr(beg, sep - beg);
859 		beg = sep + 1;
860 		// remove whitespace
861 		while (fileExtension.length() > 0
862 		        && (fileExtension[0] == ' ' || fileExtension[0] == '\t'))
863 			fileExtension = fileExtension.erase(0, 1);
864 		while (fileExtension.length() > 0
865 		        && (fileExtension[fileExtension.length() - 1] == ' '
866 		            || fileExtension[fileExtension.length() - 1] == '\t'))
867 			fileExtension = fileExtension.erase(fileExtension.length() - 1, 1);
868 		if (fileExtension.length() > 0)
869 			targetFilenameVector.emplace_back(fileExtension);
870 	}
871 	if (targetFilenameVector.size() == 0)
872 	{
873 		fprintf(stderr, _("Missing filename in %s\n"), targetFilename_.c_str());
874 		error();
875 	}
876 }
877 
878 // initialize output end of line
initializeOutputEOL(LineEndFormat lineEndFormat)879 void ASConsole::initializeOutputEOL(LineEndFormat lineEndFormat)
880 {
881 	assert(lineEndFormat == LINEEND_DEFAULT
882 	       || lineEndFormat == LINEEND_WINDOWS
883 	       || lineEndFormat == LINEEND_LINUX
884 	       || lineEndFormat == LINEEND_MACOLD);
885 
886 	outputEOL.clear();			// current line end
887 	prevEOL.clear();			// previous line end
888 	lineEndsMixed = false;		// output has mixed line ends, LINEEND_DEFAULT only
889 
890 	if (lineEndFormat == LINEEND_WINDOWS)
891 		outputEOL = "\r\n";
892 	else if (lineEndFormat == LINEEND_LINUX)
893 		outputEOL = "\n";
894 	else if (lineEndFormat == LINEEND_MACOLD)
895 		outputEOL = "\r";
896 	else
897 		outputEOL.clear();
898 }
899 
900 // read a file into the stringstream 'in'
readFile(const string & fileName_,stringstream & in) const901 FileEncoding ASConsole::readFile(const string& fileName_, stringstream& in) const
902 {
903 	const int blockSize = 65536;	// 64 KB
904 	ifstream fin(fileName_.c_str(), ios::binary);
905 	if (!fin)
906 		error("Cannot open file", fileName_.c_str());
907 	char* data = new (nothrow) char[blockSize];
908 	if (data == nullptr)
909 		error("Cannot allocate memory to open file", fileName_.c_str());
910 	fin.read(data, blockSize);
911 	if (fin.bad())
912 		error("Cannot read file", fileName_.c_str());
913 	size_t dataSize = static_cast<size_t>(fin.gcount());
914 	FileEncoding encoding = detectEncoding(data, dataSize);
915 	if (encoding == UTF_32BE || encoding == UTF_32LE)
916 		error(_("Cannot process UTF-32 encoding"), fileName_.c_str());
917 	bool firstBlock = true;
918 	bool isBigEndian = (encoding == UTF_16BE);
919 	while (dataSize != 0)
920 	{
921 		if (encoding == UTF_16LE || encoding == UTF_16BE)
922 		{
923 			// convert utf-16 to utf-8
924 			size_t utf8Size = encode.utf8LengthFromUtf16(data, dataSize, isBigEndian);
925 			char* utf8Out = new (nothrow) char[utf8Size];
926 			if (utf8Out == nullptr)
927 				error("Cannot allocate memory for utf-8 conversion", fileName_.c_str());
928 			size_t utf8Len = encode.utf16ToUtf8(data, dataSize, isBigEndian, firstBlock, utf8Out);
929 			assert(utf8Len <= utf8Size);
930 			in << string(utf8Out, utf8Len);
931 			delete[] utf8Out;
932 		}
933 		else
934 			in << string(data, dataSize);
935 		fin.read(data, blockSize);
936 		if (fin.bad())
937 			error("Cannot read file", fileName_.c_str());
938 		dataSize = static_cast<size_t>(fin.gcount());
939 		firstBlock = false;
940 	}
941 	fin.close();
942 	delete[] data;
943 	return encoding;
944 }
945 
setIgnoreExcludeErrors(bool state)946 void ASConsole::setIgnoreExcludeErrors(bool state)
947 { ignoreExcludeErrors = state; }
948 
setIgnoreExcludeErrorsAndDisplay(bool state)949 void ASConsole::setIgnoreExcludeErrorsAndDisplay(bool state)
950 { ignoreExcludeErrors = state; ignoreExcludeErrorsDisplay = state; }
951 
setIsFormattedOnly(bool state)952 void ASConsole::setIsFormattedOnly(bool state)
953 { isFormattedOnly = state; }
954 
setIsQuiet(bool state)955 void ASConsole::setIsQuiet(bool state)
956 { isQuiet = state; }
957 
setIsRecursive(bool state)958 void ASConsole::setIsRecursive(bool state)
959 { isRecursive = state; }
960 
setIsDryRun(bool state)961 void ASConsole::setIsDryRun(bool state)
962 { isDryRun = state; }
963 
setIsVerbose(bool state)964 void ASConsole::setIsVerbose(bool state)
965 { isVerbose = state; }
966 
setNoBackup(bool state)967 void ASConsole::setNoBackup(bool state)
968 { noBackup = state; }
969 
setOptionFileName(const string & name)970 void ASConsole::setOptionFileName(const string& name)
971 { optionFileName = name; }
972 
setOrigSuffix(const string & suffix)973 void ASConsole::setOrigSuffix(const string& suffix)
974 { origSuffix = suffix; }
975 
setPreserveDate(bool state)976 void ASConsole::setPreserveDate(bool state)
977 { preserveDate = state; }
978 
setProjectOptionFileName(const string & optfilepath)979 void ASConsole::setProjectOptionFileName(const string& optfilepath)
980 { projectOptionFileName = optfilepath; }
981 
setStdPathIn(const string & path)982 void ASConsole::setStdPathIn(const string& path)
983 { stdPathIn = path; }
984 
setStdPathOut(const string & path)985 void ASConsole::setStdPathOut(const string& path)
986 { stdPathOut = path; }
987 
988 // set outputEOL variable
setOutputEOL(LineEndFormat lineEndFormat,const string & currentEOL)989 void ASConsole::setOutputEOL(LineEndFormat lineEndFormat, const string& currentEOL)
990 {
991 	if (lineEndFormat == LINEEND_DEFAULT)
992 	{
993 		outputEOL = currentEOL;
994 		if (prevEOL.empty())
995 			prevEOL = outputEOL;
996 		if (prevEOL != outputEOL)
997 		{
998 			lineEndsMixed = true;
999 			filesAreIdentical = false;
1000 			prevEOL = outputEOL;
1001 		}
1002 	}
1003 	else
1004 	{
1005 		prevEOL = currentEOL;
1006 		if (prevEOL != outputEOL)
1007 			filesAreIdentical = false;
1008 	}
1009 }
1010 
1011 #ifdef _WIN32  // Windows specific
1012 
1013 /**
1014  * WINDOWS function to display the last system error.
1015  */
displayLastError()1016 void ASConsole::displayLastError()
1017 {
1018 	LPSTR msgBuf;
1019 	DWORD lastError = GetLastError();
1020 	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
1021 	              nullptr,
1022 	              lastError,
1023 	              MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),  // Default language
1024 	              (LPSTR) &msgBuf,
1025 	              0,
1026 	              nullptr
1027 	             );
1028 	// Display the string.
1029 	(*errorStream) << "Error (" << lastError << ") " << msgBuf << endl;
1030 	// Free the buffer.
1031 	LocalFree(msgBuf);
1032 }
1033 
1034 /**
1035  * WINDOWS function to get the current directory.
1036  * NOTE: getenv("CD") does not work for Windows Vista.
1037  *        The Windows function GetCurrentDirectory is used instead.
1038  *
1039  * @return              The path of the current directory
1040  */
getCurrentDirectory(const string & fileName_) const1041 string ASConsole::getCurrentDirectory(const string& fileName_) const
1042 {
1043 	char currdir[MAX_PATH];
1044 	currdir[0] = '\0';
1045 	if (!GetCurrentDirectory(sizeof(currdir), currdir))
1046 		error("Cannot find file", fileName_.c_str());
1047 	return string(currdir);
1048 }
1049 
1050 /**
1051  * WINDOWS function to resolve wildcards and recurse into sub directories.
1052  * The fileName vector is filled with the path and names of files to process.
1053  *
1054  * @param directory     The path of the directory to be processed.
1055  * @param wildcards     A vector of wildcards to be processed (e.g. *.cpp).
1056  */
getFileNames(const string & directory,const vector<string> & wildcards)1057 void ASConsole::getFileNames(const string& directory, const vector<string>& wildcards)
1058 {
1059 	vector<string> subDirectory;    // sub directories of directory
1060 	WIN32_FIND_DATA findFileData;   // for FindFirstFile and FindNextFile
1061 
1062 	// Find the first file in the directory
1063 	// Find will get at least "." and "..".
1064 	string firstFile = directory + "\\*";
1065 	HANDLE hFind = FindFirstFile(firstFile.c_str(), &findFileData);
1066 
1067 	if (hFind == INVALID_HANDLE_VALUE)
1068 	{
1069 		// Error (3) The system cannot find the path specified.
1070 		// Error (123) The filename, directory name, or volume label syntax is incorrect.
1071 		// ::FindClose(hFind); before exiting
1072 		displayLastError();
1073 		error(_("Cannot open directory"), directory.c_str());
1074 	}
1075 
1076 	// save files and sub directories
1077 	do
1078 	{
1079 		// skip hidden or read only
1080 		if (findFileData.cFileName[0] == '.'
1081 		        || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
1082 		        || (findFileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
1083 			continue;
1084 
1085 		// is this a sub directory
1086 		if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1087 		{
1088 			if (!isRecursive)
1089 				continue;
1090 			// if a sub directory and recursive, save sub directory
1091 			string subDirectoryPath = directory + g_fileSeparator + findFileData.cFileName;
1092 			if (isPathExclued(subDirectoryPath))
1093 				printMsg(_("Exclude  %s\n"), subDirectoryPath.substr(mainDirectoryLength));
1094 			else
1095 				subDirectory.emplace_back(subDirectoryPath);
1096 			continue;
1097 		}
1098 
1099 		string filePathName = directory + g_fileSeparator + findFileData.cFileName;
1100 		// check exclude before wildcmp to avoid "unmatched exclude" error
1101 		bool isExcluded = isPathExclued(filePathName);
1102 		// save file name if wildcard match
1103 		for (size_t i = 0; i < wildcards.size(); i++)
1104 		{
1105 			if (wildcmp(wildcards[i].c_str(), findFileData.cFileName))
1106 			{
1107 				if (isExcluded)
1108 					printMsg(_("Exclude  %s\n"), filePathName.substr(mainDirectoryLength));
1109 				else
1110 					fileName.emplace_back(filePathName);
1111 				break;
1112 			}
1113 		}
1114 	}
1115 	while (FindNextFile(hFind, &findFileData) != 0);
1116 
1117 	// check for processing error
1118 	::FindClose(hFind);
1119 	DWORD dwError = GetLastError();
1120 	if (dwError != ERROR_NO_MORE_FILES)
1121 		error("Error processing directory", directory.c_str());
1122 
1123 	// recurse into sub directories
1124 	// if not doing recursive subDirectory is empty
1125 	for (unsigned i = 0; i < subDirectory.size(); i++)
1126 		getFileNames(subDirectory[i], wildcards);
1127 
1128 	return;
1129 }
1130 
1131 // WINDOWS function to get the full path name from the relative path name
1132 // Return the full path name or an empty string if failed.
getFullPathName(const string & relativePath) const1133 string ASConsole::getFullPathName(const string& relativePath) const
1134 {
1135 	char fullPath[MAX_PATH];
1136 	GetFullPathName(relativePath.c_str(), MAX_PATH, fullPath, NULL);
1137 	return fullPath;
1138 }
1139 
1140 /**
1141  * WINDOWS function to format a number according to the current locale.
1142  * This formats positive integers only, no float.
1143  *
1144  * @param num		The number to be formatted.
1145  * @param lcid		The LCID of the locale to be used for testing.
1146  * @return			The formatted number.
1147  */
getNumberFormat(int num,size_t lcid) const1148 string ASConsole::getNumberFormat(int num, size_t lcid) const
1149 {
1150 #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
1151 	// Compilers that don't support C++ locales should still support this assert.
1152 	// The C locale should be set but not the C++.
1153 	// This function is not necessary if the C++ locale is set.
1154 	// The locale().name() return value is not portable to all compilers.
1155 	assert(locale().name() == "C");
1156 #endif
1157 	// convert num to a string
1158 	stringstream alphaNum;
1159 	alphaNum << num;
1160 	string number = alphaNum.str();
1161 	if (useAscii)
1162 		return number;
1163 
1164 	// format the number using the Windows API
1165 	if (lcid == 0)
1166 		lcid = LOCALE_USER_DEFAULT;
1167 	int outSize = ::GetNumberFormat(lcid, 0, number.c_str(), nullptr, nullptr, 0);
1168 	char* outBuf = new (nothrow) char[outSize];
1169 	if (outBuf == nullptr)
1170 		return number;
1171 	::GetNumberFormat(lcid, 0, number.c_str(), nullptr, outBuf, outSize);
1172 	string formattedNum(outBuf);
1173 	delete[] outBuf;
1174 	// remove the decimal
1175 	int decSize = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, nullptr, 0);
1176 	char* decBuf = new (nothrow) char[decSize];
1177 	if (decBuf == nullptr)
1178 		return number;
1179 	::GetLocaleInfo(lcid, LOCALE_SDECIMAL, decBuf, decSize);
1180 	size_t i = formattedNum.rfind(decBuf);
1181 	delete[] decBuf;
1182 	if (i != string::npos)
1183 		formattedNum.erase(i);
1184 	if (!formattedNum.length())
1185 		formattedNum = "0";
1186 	return formattedNum;
1187 }
1188 
1189 /**
1190  * WINDOWS function to check for a HOME directory
1191  *
1192  * @param absPath       The path to be evaluated.
1193  * @returns             true if absPath is HOME or is an invalid absolute
1194  *                      path, false otherwise.
1195  */
isHomeOrInvalidAbsPath(const string & absPath) const1196 bool ASConsole::isHomeOrInvalidAbsPath(const string& absPath) const
1197 {
1198 	char* env = getenv("USERPROFILE");
1199 	if (env == nullptr)
1200 		return true;
1201 
1202 	if (absPath.c_str() == env)
1203 		return true;
1204 
1205 	if (absPath.compare(0, strlen(env), env) != 0)
1206 		return true;
1207 
1208 	return false;
1209 }
1210 
1211 /**
1212  * WINDOWS function to open a HTML file in the default browser.
1213  */
launchDefaultBrowser(const char * filePathIn) const1214 void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
1215 {
1216 	struct stat statbuf;
1217 	const char* envPaths[] = { "PROGRAMFILES(X86)", "PROGRAMFILES" };
1218 	size_t pathsLen = sizeof(envPaths) / sizeof(envPaths[0]);
1219 	string htmlDefaultPath;
1220 	for (size_t i = 0; i < pathsLen; i++)
1221 	{
1222 		const char* envPath = getenv(envPaths[i]);
1223 		if (envPath == nullptr)
1224 			continue;
1225 		htmlDefaultPath = envPath;
1226 		if (htmlDefaultPath.length() > 0
1227 		        && htmlDefaultPath[htmlDefaultPath.length() - 1] == g_fileSeparator)
1228 			htmlDefaultPath.erase(htmlDefaultPath.length() - 1);
1229 		htmlDefaultPath.append("\\AStyle\\doc");
1230 		if (stat(htmlDefaultPath.c_str(), &statbuf) == 0 && statbuf.st_mode & S_IFDIR)
1231 			break;
1232 	}
1233 	htmlDefaultPath.append("\\");
1234 
1235 	// build file path
1236 	string htmlFilePath;
1237 	if (filePathIn == nullptr)
1238 		htmlFilePath = htmlDefaultPath + "astyle.html";
1239 	else
1240 	{
1241 		if (strpbrk(filePathIn, "\\/") == nullptr)
1242 			htmlFilePath = htmlDefaultPath + filePathIn;
1243 		else
1244 			htmlFilePath = filePathIn;
1245 	}
1246 	standardizePath(htmlFilePath);
1247 	if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
1248 	{
1249 		printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
1250 		return;
1251 	}
1252 
1253 	SHELLEXECUTEINFO sei = { sizeof(sei), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1254 	sei.fMask = SEE_MASK_FLAG_NO_UI;
1255 	sei.lpVerb = "open";
1256 	sei.lpFile = htmlFilePath.c_str();
1257 	sei.nShow = SW_SHOWNORMAL;
1258 
1259 	// browser open will be bypassed in test programs
1260 	printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
1261 	if (!bypassBrowserOpen)
1262 	{
1263 		int ret = ShellExecuteEx(&sei);
1264 		if (!ret)
1265 			error(_("Command execute failure"), htmlFilePath.c_str());
1266 	}
1267 }
1268 
1269 #else  // Linux specific
1270 
1271 /**
1272  * LINUX function to get the current directory.
1273  * This is done if the fileName does not contain a path.
1274  * It is probably from an editor sending a single file.
1275  *
1276  * @param fileName_     The filename is used only for  the error message.
1277  * @return              The path of the current directory
1278  */
getCurrentDirectory(const string & fileName_) const1279 string ASConsole::getCurrentDirectory(const string& fileName_) const
1280 {
1281 	char* currdir = getenv("PWD");
1282 	if (currdir == nullptr)
1283 		error("Cannot find file", fileName_.c_str());
1284 	return string(currdir);
1285 }
1286 
1287 /**
1288  * LINUX function to resolve wildcards and recurse into sub directories.
1289  * The fileName vector is filled with the path and names of files to process.
1290  *
1291  * @param directory     The path of the directory to be processed.
1292  * @param wildcards     A vector of wildcards to be processed (e.g. *.cpp).
1293  */
getFileNames(const string & directory,const vector<string> & wildcards)1294 void ASConsole::getFileNames(const string& directory, const vector<string>& wildcards)
1295 {
1296 	struct dirent* entry;           // entry from readdir()
1297 	struct stat statbuf;            // entry from stat()
1298 	vector<string> subDirectory;    // sub directories of this directory
1299 
1300 	// errno is defined in <errno.h> and is set for errors in opendir, readdir, or stat
1301 	errno = 0;
1302 
1303 	DIR* dp = opendir(directory.c_str());
1304 	if (dp == nullptr)
1305 		error(_("Cannot open directory"), directory.c_str());
1306 
1307 	// save the first fileName entry for this recursion
1308 	const unsigned firstEntry = fileName.size();
1309 
1310 	// save files and sub directories
1311 	while ((entry = readdir(dp)) != nullptr)
1312 	{
1313 		// get file status
1314 		string entryFilepath = directory + g_fileSeparator + entry->d_name;
1315 		if (stat(entryFilepath.c_str(), &statbuf) != 0)
1316 		{
1317 			if (errno == EOVERFLOW)         // file over 2 GB is OK
1318 			{
1319 				errno = 0;
1320 				continue;
1321 			}
1322 			perror("errno message");
1323 			error("Error getting file status in directory", directory.c_str());
1324 		}
1325 		// skip hidden or read only
1326 		if (entry->d_name[0] == '.' || !(statbuf.st_mode & S_IWUSR))
1327 			continue;
1328 		// if a sub directory and recursive, save sub directory
1329 		if (S_ISDIR(statbuf.st_mode) && isRecursive)
1330 		{
1331 			if (isPathExclued(entryFilepath))
1332 				printMsg(_("Exclude  %s\n"), entryFilepath.substr(mainDirectoryLength));
1333 			else
1334 				subDirectory.emplace_back(entryFilepath);
1335 			continue;
1336 		}
1337 
1338 		// if a file, save file name
1339 		if (S_ISREG(statbuf.st_mode))
1340 		{
1341 			// check exclude before wildcmp to avoid "unmatched exclude" error
1342 			bool isExcluded = isPathExclued(entryFilepath);
1343 			// save file name if wildcard match
1344 			for (string wildcard : wildcards)
1345 			{
1346 				if (wildcmp(wildcard.c_str(), entry->d_name) != 0)
1347 				{
1348 					if (isExcluded)
1349 						printMsg(_("Exclude  %s\n"), entryFilepath.substr(mainDirectoryLength));
1350 					else
1351 						fileName.emplace_back(entryFilepath);
1352 					break;
1353 				}
1354 			}
1355 		}
1356 	}
1357 
1358 	if (closedir(dp) != 0)
1359 	{
1360 		perror("errno message");
1361 		error("Error reading directory", directory.c_str());
1362 	}
1363 
1364 	// sort the current entries for fileName
1365 	if (firstEntry < fileName.size())
1366 		sort(&fileName[firstEntry], &fileName[fileName.size()]);
1367 
1368 	// recurse into sub directories
1369 	// if not doing recursive, subDirectory is empty
1370 	if (subDirectory.size() > 1)
1371 		sort(subDirectory.begin(), subDirectory.end());
1372 	for (unsigned i = 0; i < subDirectory.size(); i++)
1373 	{
1374 		getFileNames(subDirectory[i], wildcards);
1375 	}
1376 }
1377 
1378 // LINUX function to get the full path name from the relative path name
1379 // Return the full path name or an empty string if failed.
getFullPathName(const string & relativePath) const1380 string ASConsole::getFullPathName(const string& relativePath) const
1381 {
1382 	// ignore realPath attribute warning
1383 #pragma GCC diagnostic push
1384 #pragma GCC diagnostic ignored "-Wunused-result"
1385 	char fullPath[PATH_MAX];
1386 	realpath(relativePath.c_str(), fullPath);
1387 	return fullPath;
1388 #pragma GCC diagnostic pop
1389 }
1390 
1391 /**
1392  * LINUX function to get locale information and call getNumberFormat.
1393  * This formats positive integers only, no float.
1394  *
1395  * @param num		The number to be formatted.
1396  *                  size_t is for compatibility with the Windows function.
1397  * @return			The formatted number.
1398  */
getNumberFormat(int num,size_t) const1399 string ASConsole::getNumberFormat(int num, size_t /*lcid*/) const
1400 {
1401 #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__BORLANDC__) || defined(__GNUC__)
1402 	// Compilers that don't support C++ locales should still support this assert.
1403 	// The C locale should be set but not the C++.
1404 	// This function is not necessary if the C++ locale is set.
1405 	// The locale().name() return value is not portable to all compilers.
1406 	assert(locale().name() == "C");
1407 #endif
1408 
1409 	// get the locale info
1410 	struct lconv* lc;
1411 	lc = localeconv();
1412 
1413 	// format the number
1414 	return getNumberFormat(num, lc->grouping, lc->thousands_sep);
1415 }
1416 
1417 /**
1418  * LINUX function to format a number according to the current locale.
1419  * This formats positive integers only, no float.
1420  *
1421  * @param num			The number to be formatted.
1422  * @param groupingArg   The grouping string from the locale.
1423  * @param  separator	The thousands group separator from the locale.
1424  * @return				The formatted number.
1425  */
getNumberFormat(int num,const char * groupingArg,const char * separator) const1426 string ASConsole::getNumberFormat(int num, const char* groupingArg, const char* separator) const
1427 {
1428 	// convert num to a string
1429 	stringstream alphaNum;
1430 	alphaNum << num;
1431 	string number = alphaNum.str();
1432 	// format the number from right to left
1433 	string formattedNum;
1434 	size_t ig = 0;	// grouping index
1435 	int grouping = groupingArg[ig];
1436 	int i = number.length();
1437 	// check for no grouping
1438 	if (grouping == 0)
1439 		grouping = number.length();
1440 	while (i > 0)
1441 	{
1442 		// extract a group of numbers
1443 		string group;
1444 		if (i < grouping)
1445 			group = number;
1446 		else
1447 			group = number.substr(i - grouping);
1448 		// update formatted number
1449 		formattedNum.insert(0, group);
1450 		i -= grouping;
1451 		if (i < 0)
1452 			i = 0;
1453 		if (i > 0)
1454 			formattedNum.insert(0, separator);
1455 		number.erase(i);
1456 		// update grouping
1457 		if (groupingArg[ig] != '\0'
1458 		        && groupingArg[ig + 1] != '\0')
1459 			grouping = groupingArg[++ig];
1460 	}
1461 	return formattedNum;
1462 }
1463 
1464 /**
1465  * LINUX function to check for a HOME directory
1466  *
1467  * @param absPath       The path to be evaluated.
1468  * @returns             true if absPath is HOME or is an invalid absolute
1469  *                      path, false otherwise.
1470  */
isHomeOrInvalidAbsPath(const string & absPath) const1471 bool ASConsole::isHomeOrInvalidAbsPath(const string& absPath) const
1472 {
1473 	char* env = getenv("HOME");
1474 	if (env == nullptr)
1475 		return true;
1476 
1477 	if (absPath.c_str() == env)
1478 		return true;
1479 
1480 	if (absPath.compare(0, strlen(env), env) != 0)
1481 		return true;
1482 
1483 	return false;
1484 }
1485 
1486 /**
1487  * LINUX function to open a HTML file in the default browser.
1488  * Use xdg-open from freedesktop.org cross-desktop compatibility suite xdg-utils.
1489  * see http://portland.freedesktop.org/wiki/
1490  * This is installed on most modern distributions.
1491  */
launchDefaultBrowser(const char * filePathIn) const1492 void ASConsole::launchDefaultBrowser(const char* filePathIn /*nullptr*/) const
1493 {
1494 	struct stat statbuf;
1495 	string htmlDefaultPath = "/usr/share/doc/astyle/html/";
1496 	string htmlDefaultFile = "astyle.html";
1497 
1498 	// build file path
1499 	string htmlFilePath;
1500 	if (filePathIn == nullptr)
1501 		htmlFilePath = htmlDefaultPath + htmlDefaultFile;
1502 	else
1503 	{
1504 		if (strpbrk(filePathIn, "\\/") == nullptr)
1505 			htmlFilePath = htmlDefaultPath + filePathIn;
1506 		else
1507 			htmlFilePath = filePathIn;
1508 	}
1509 	standardizePath(htmlFilePath);
1510 	if (stat(htmlFilePath.c_str(), &statbuf) != 0 || !(statbuf.st_mode & S_IFREG))
1511 	{
1512 		printf(_("Cannot open HTML file %s\n"), htmlFilePath.c_str());
1513 		return;
1514 	}
1515 
1516 	// get search paths
1517 	const char* envPaths = getenv("PATH");
1518 	if (envPaths == nullptr)
1519 		envPaths = "?";
1520 	size_t envlen = strlen(envPaths);
1521 	char* paths = new char[envlen + 1];
1522 	strcpy(paths, envPaths);
1523 	// find xdg-open (usually in /usr/bin)
1524 	// Mac uses open instead
1525 #ifdef __APPLE__
1526 	const char* fileOpen = "open";
1527 #else
1528 	const char* fileOpen = "xdg-open";
1529 #endif
1530 	string searchPath;
1531 	char* searchDir = strtok(paths, ":");
1532 	while (searchDir != nullptr)
1533 	{
1534 		searchPath = searchDir;
1535 		if (searchPath.length() > 0
1536 		        && searchPath[searchPath.length() - 1] != g_fileSeparator)
1537 			searchPath.append(string(1, g_fileSeparator));
1538 		searchPath.append(fileOpen);
1539 		if (stat(searchPath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
1540 			break;
1541 		searchDir = strtok(nullptr, ":");
1542 	}
1543 	delete[] paths;
1544 	if (searchDir == nullptr)
1545 		error(_("Command is not installed"), fileOpen);
1546 
1547 	// browser open will be bypassed in test programs
1548 	printf(_("Opening HTML documentation %s\n"), htmlFilePath.c_str());
1549 	if (!bypassBrowserOpen)
1550 	{
1551 		execlp(fileOpen, fileOpen, htmlFilePath.c_str(), nullptr);
1552 		// execlp will NOT return if successful
1553 		error(_("Command execute failure"), fileOpen);
1554 	}
1555 }
1556 
1557 #endif  // _WIN32
1558 
1559 /**
1560  * Returns the parent directory of absPath. If absPath is not a valid absolute
1561  * path or if it does not have a parent, an empty string is returned.
1562  *
1563  * @param absPath       The initial directory.
1564  * @return              The parent directory of absPath, or an empty string if
1565  *                      one cannot be found.
1566  */
getParentDirectory(const string & absPath) const1567 string ASConsole::getParentDirectory(const string& absPath) const
1568 {
1569 	if (isHomeOrInvalidAbsPath(absPath))
1570 	{
1571 		return string();
1572 	}
1573 	size_t offset = absPath.size() - 1;
1574 	if (absPath[absPath.size() - 1] == g_fileSeparator)
1575 	{
1576 		offset -= 1;
1577 	}
1578 	size_t idx = absPath.rfind(g_fileSeparator, offset);
1579 	if (idx == string::npos)
1580 	{
1581 		return string();
1582 	}
1583 	string str = absPath.substr(0, idx + 1);
1584 	return str;
1585 }
1586 
1587 // get individual file names from the command-line file path
getFilePaths(const string & filePath)1588 void ASConsole::getFilePaths(const string& filePath)
1589 {
1590 	fileName.clear();
1591 	targetDirectory = string();
1592 	targetFilename = string();
1593 	vector<string> targetFilenameVector;
1594 
1595 	// separate directory and file name
1596 	size_t separator = filePath.find_last_of(g_fileSeparator);
1597 	if (separator == string::npos)
1598 	{
1599 		// if no directory is present, use the currently active directory
1600 		targetDirectory = getCurrentDirectory(filePath);
1601 		targetFilename  = filePath;
1602 		mainDirectoryLength = targetDirectory.length() + 1;    // +1 includes trailing separator
1603 	}
1604 	else
1605 	{
1606 		targetDirectory = filePath.substr(0, separator);
1607 		targetFilename  = filePath.substr(separator + 1);
1608 		mainDirectoryLength = targetDirectory.length() + 1;    // +1 includes trailing separator
1609 	}
1610 
1611 	if (targetFilename.length() == 0)
1612 	{
1613 		fprintf(stderr, _("Missing filename in %s\n"), filePath.c_str());
1614 		error();
1615 	}
1616 
1617 	// check filename for wildcards
1618 	hasWildcard = false;
1619 	if (targetFilename.find_first_of("*?") != string::npos)
1620 		hasWildcard = true;
1621 
1622 	// If the filename is not quoted on Linux, bash will replace the
1623 	// wildcard instead of passing it to the program.
1624 	if (isRecursive && !hasWildcard)
1625 	{
1626 		fprintf(stderr, "%s\n", _("Recursive option with no wildcard"));
1627 #ifndef _WIN32
1628 		fprintf(stderr, "%s\n", _("Did you intend quote the filename"));
1629 #endif
1630 		error();
1631 	}
1632 
1633 	bool hasMultipleTargets = false;
1634 	if (targetFilename.find_first_of(",;") != string::npos)
1635 		hasMultipleTargets = true;
1636 
1637 	// display directory name for wildcard processing
1638 	if (hasWildcard)
1639 	{
1640 		printSeparatingLine();
1641 		printMsg(_("Directory  %s\n"), targetDirectory + g_fileSeparator + targetFilename);
1642 	}
1643 
1644 	// clear exclude hits vector
1645 	size_t excludeHitsVectorSize = excludeHitsVector.size();
1646 	for (size_t ix = 0; ix < excludeHitsVectorSize; ix++)
1647 		excludeHitsVector[ix] = false;
1648 
1649 	// create a vector of paths and file names to process
1650 	if (hasWildcard || isRecursive || hasMultipleTargets)
1651 	{
1652 		getTargetFilenames(targetFilename, targetFilenameVector);
1653 		getFileNames(targetDirectory, targetFilenameVector);
1654 	}
1655 	else
1656 	{
1657 		// verify a single file is not a directory (needed on Linux)
1658 		string entryFilepath = targetDirectory + g_fileSeparator + targetFilename;
1659 		struct stat statbuf;
1660 		if (stat(entryFilepath.c_str(), &statbuf) == 0 && (statbuf.st_mode & S_IFREG))
1661 			fileName.emplace_back(entryFilepath);
1662 	}
1663 
1664 	// check for unprocessed excludes
1665 	bool excludeErr = false;
1666 	for (size_t ix = 0; ix < excludeHitsVector.size(); ix++)
1667 	{
1668 		if (!excludeHitsVector[ix])
1669 		{
1670 			excludeErr = true;
1671 			if (!ignoreExcludeErrorsDisplay)
1672 			{
1673 				if (ignoreExcludeErrors)
1674 					printMsg(_("Exclude (unmatched)  %s\n"), excludeVector[ix]);
1675 				else
1676 					fprintf(stderr, _("Exclude (unmatched)  %s\n"), excludeVector[ix].c_str());
1677 			}
1678 			else
1679 			{
1680 				if (!ignoreExcludeErrors)
1681 					fprintf(stderr, _("Exclude (unmatched)  %s\n"), excludeVector[ix].c_str());
1682 			}
1683 		}
1684 	}
1685 
1686 	if (excludeErr && !ignoreExcludeErrors)
1687 	{
1688 		if (hasWildcard && !isRecursive)
1689 			fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
1690 		error();
1691 	}
1692 
1693 	// check if files were found (probably an input error if not)
1694 	if (fileName.empty())
1695 	{
1696 		fprintf(stderr, _("No file to process %s\n"), filePath.c_str());
1697 		if (hasWildcard && !isRecursive)
1698 			fprintf(stderr, "%s\n", _("Did you intend to use --recursive"));
1699 		error();
1700 	}
1701 
1702 	if (hasWildcard)
1703 		printSeparatingLine();
1704 }
1705 
1706 // Check if a file exists
fileExists(const char * file) const1707 bool ASConsole::fileExists(const char* file) const
1708 {
1709 	struct stat buf;
1710 	return (stat(file, &buf) == 0);
1711 }
1712 
fileNameVectorIsEmpty() const1713 bool ASConsole::fileNameVectorIsEmpty() const
1714 {
1715 	return fileNameVector.empty();
1716 }
1717 
isOption(const string & arg,const char * op)1718 bool ASConsole::isOption(const string& arg, const char* op)
1719 {
1720 	return arg.compare(op) == 0;
1721 }
1722 
isOption(const string & arg,const char * a,const char * b)1723 bool ASConsole::isOption(const string& arg, const char* a, const char* b)
1724 {
1725 	return (isOption(arg, a) || isOption(arg, b));
1726 }
1727 
isParamOption(const string & arg,const char * option)1728 bool ASConsole::isParamOption(const string& arg, const char* option)
1729 {
1730 	bool retVal = arg.compare(0, strlen(option), option) == 0;
1731 	// if comparing for short option, 2nd char of arg must be numeric
1732 	if (retVal && strlen(option) == 1 && arg.length() > 1)
1733 		if (!isdigit((unsigned char) arg[1]))
1734 			retVal = false;
1735 	return retVal;
1736 }
1737 
1738 // compare a path to the exclude vector
1739 // used for both directories and filenames
1740 // updates the g_excludeHitsVector
1741 // return true if a match
isPathExclued(const string & subPath)1742 bool ASConsole::isPathExclued(const string& subPath)
1743 {
1744 	bool retVal = false;
1745 
1746 	// read the exclude vector checking for a match
1747 	for (size_t i = 0; i < excludeVector.size(); i++)
1748 	{
1749 		string exclude = excludeVector[i];
1750 
1751 		if (subPath.length() < exclude.length())
1752 			continue;
1753 
1754 		size_t compareStart = subPath.length() - exclude.length();
1755 		// subPath compare must start with a directory name
1756 		if (compareStart > 0)
1757 		{
1758 			char lastPathChar = subPath[compareStart - 1];
1759 			if (lastPathChar != g_fileSeparator)
1760 				continue;
1761 		}
1762 
1763 		string compare = subPath.substr(compareStart);
1764 		if (!g_isCaseSensitive)
1765 		{
1766 			// make it case insensitive for Windows
1767 			for (size_t j = 0; j < compare.length(); j++)
1768 				compare[j] = (char) tolower(compare[j]);
1769 			for (size_t j = 0; j < exclude.length(); j++)
1770 				exclude[j] = (char) tolower(exclude[j]);
1771 		}
1772 		// compare sub directory to exclude data - must check them all
1773 		if (compare == exclude)
1774 		{
1775 			excludeHitsVector[i] = true;
1776 			retVal = true;
1777 			break;
1778 		}
1779 	}
1780 	return retVal;
1781 }
1782 
printHelp() const1783 void ASConsole::printHelp() const
1784 {
1785 	cout << endl;
1786 	cout << "                     Artistic Style " << g_version << endl;
1787 	cout << "                     Maintained by: Jim Pattee\n";
1788 	cout << "                     Original Author: Tal Davidson\n";
1789 	cout << endl;
1790 	cout << "Usage:\n";
1791 	cout << "------\n";
1792 	cout << "            astyle [OPTIONS] File1 File2 File3 [...]\n";
1793 	cout << endl;
1794 	cout << "            astyle [OPTIONS] < Original > Beautified\n";
1795 	cout << endl;
1796 	cout << "    When indenting a specific file, the resulting indented file RETAINS\n";
1797 	cout << "    the original file-name. The original pre-indented file is renamed,\n";
1798 	cout << "    with a suffix of \'.orig\' added to the original filename.\n";
1799 	cout << endl;
1800 	cout << "    Wildcards (* and ?) may be used in the filename.\n";
1801 	cout << "    A \'recursive\' option can process directories recursively.\n";
1802 	cout << "    Multiple file extensions may be separated by a comma.\n";
1803 	cout << endl;
1804 	cout << "    By default, astyle is set up to indent with four spaces per indent,\n";
1805 	cout << "    a maximal indentation of 40 spaces inside continuous statements,\n";
1806 	cout << "    a minimum indentation of eight spaces inside conditional statements,\n";
1807 	cout << "    and NO formatting options.\n";
1808 	cout << endl;
1809 	cout << "Options:\n";
1810 	cout << "--------\n";
1811 	cout << "    This  program  follows  the  usual  GNU  command line syntax.\n";
1812 	cout << "    Long options (starting with '--') must be written one at a time.\n";
1813 	cout << "    Short options (starting with '-') may be appended together.\n";
1814 	cout << "    Thus, -bps4 is the same as -b -p -s4.\n";
1815 	cout << endl;
1816 	cout << "Option Files:\n";
1817 	cout << "-------------\n";
1818 	cout << "    Artistic Style looks for a default option file and/or a project\n";
1819 	cout << "    option file in the following order:\n";
1820 	cout << "    1. The command line options have precedence.\n";
1821 	cout << "    2. The project option file has precedence over the default file\n";
1822 	cout << "       o the file name indicated by the --project= command line option.\n";
1823 	cout << "       o the file named .astylerc or _ astylerc.\n";
1824 	cout << "       o the file name identified by ARTISTIC_STYLE_PROJECT_OPTIONS.\n";
1825 	cout << "       o the file is disabled by --project=none on the command line.\n";
1826 	cout << "    3. The default option file that can be used for all projects.\n";
1827 	cout << "       o the file path indicated by the --options= command line option.\n";
1828 	cout << "       o the file path indicated by ARTISTIC_STYLE_OPTIONS.\n";
1829 	cout << "       o the file named .astylerc in the HOME directory (for Linux).\n";
1830 	cout << "       o the file name astylerc in the APPDATA directory (for Windows).\n";
1831 	cout << "       o the file is disabled by --project=none on the command line.\n";
1832 	cout << "    Long options within the option files may be written without '--'.\n";
1833 	cout << "    Line-end comments begin with a '#'.\n";
1834 	cout << endl;
1835 	cout << "Disable Formatting:\n";
1836 	cout << "-------------------\n";
1837 	cout << "    Disable Block\n";
1838 	cout << "    Blocks of code can be disabled with the comment tags *INDENT-OFF*\n";
1839 	cout << "    and *INDENT-ON*. It must be contained in a one-line comment.\n";
1840 	cout << endl;
1841 	cout << "    Disable Line\n";
1842 	cout << "    Padding of operators can be disabled on a single line using the\n";
1843 	cout << "    comment tag *NOPAD*. It must be contained in a line-end comment.\n";
1844 	cout << endl;
1845 	cout << "Brace Style Options:\n";
1846 	cout << "--------------------\n";
1847 	cout << "    default brace style\n";
1848 	cout << "    If no brace style is requested, the opening braces will not be\n";
1849 	cout << "    changed and closing braces will be broken from the preceding line.\n";
1850 	cout << endl;
1851 	cout << "    --style=allman  OR  --style=bsd  OR  --style=break  OR  -A1\n";
1852 	cout << "    Allman style formatting/indenting.\n";
1853 	cout << "    Broken braces.\n";
1854 	cout << endl;
1855 	cout << "    --style=java  OR  --style=attach  OR  -A2\n";
1856 	cout << "    Java style formatting/indenting.\n";
1857 	cout << "    Attached braces.\n";
1858 	cout << endl;
1859 	cout << "    --style=kr  OR  --style=k&r  OR  --style=k/r  OR  -A3\n";
1860 	cout << "    Kernighan & Ritchie style formatting/indenting.\n";
1861 	cout << "    Linux braces.\n";
1862 	cout << endl;
1863 	cout << "    --style=stroustrup  OR  -A4\n";
1864 	cout << "    Stroustrup style formatting/indenting.\n";
1865 	cout << "    Linux braces.\n";
1866 	cout << endl;
1867 	cout << "    --style=whitesmith  OR  -A5\n";
1868 	cout << "    Whitesmith style formatting/indenting.\n";
1869 	cout << "    Broken, indented braces.\n";
1870 	cout << "    Indented class blocks and switch blocks.\n";
1871 	cout << endl;
1872 	cout << "    --style=vtk  OR  -A15\n";
1873 	cout << "    VTK style formatting/indenting.\n";
1874 	cout << "    Broken, indented braces except for the opening braces.\n";
1875 	cout << endl;
1876 	cout << "    --style=ratliff  OR  --style=banner  OR  -A6\n";
1877 	cout << "    Ratliff style formatting/indenting.\n";
1878 	cout << "    Attached, indented braces.\n";
1879 	cout << endl;
1880 	cout << "    --style=gnu  OR  -A7\n";
1881 	cout << "    GNU style formatting/indenting.\n";
1882 	cout << "    Broken braces, indented blocks.\n";
1883 	cout << endl;
1884 	cout << "    --style=linux  OR  --style=knf  OR  -A8\n";
1885 	cout << "    Linux style formatting/indenting.\n";
1886 	cout << "    Linux braces, minimum conditional indent is one-half indent.\n";
1887 	cout << endl;
1888 	cout << "    --style=horstmann  OR  --style=run-in  OR  -A9\n";
1889 	cout << "    Horstmann style formatting/indenting.\n";
1890 	cout << "    Run-in braces, indented switches.\n";
1891 	cout << endl;
1892 	cout << "    --style=1tbs  OR  --style=otbs  OR  -A10\n";
1893 	cout << "    One True Brace Style formatting/indenting.\n";
1894 	cout << "    Linux braces, add braces to all conditionals.\n";
1895 	cout << endl;
1896 	cout << "    --style=google  OR  -A14\n";
1897 	cout << "    Google style formatting/indenting.\n";
1898 	cout << "    Attached braces, indented class modifiers.\n";
1899 	cout << endl;
1900 	cout << "    --style=mozilla  OR  -A16\n";
1901 	cout << "    Mozilla style formatting/indenting.\n";
1902 	cout << "    Linux braces, with broken braces for structs and enums,\n";
1903 	cout << "    and attached braces for namespaces.\n";
1904 	cout << endl;
1905 	cout << "    --style=pico  OR  -A11\n";
1906 	cout << "    Pico style formatting/indenting.\n";
1907 	cout << "    Run-in opening braces and attached closing braces.\n";
1908 	cout << "    Uses keep one line blocks and keep one line statements.\n";
1909 	cout << endl;
1910 	cout << "    --style=lisp  OR  -A12\n";
1911 	cout << "    Lisp style formatting/indenting.\n";
1912 	cout << "    Attached opening braces and attached closing braces.\n";
1913 	cout << "    Uses keep one line statements.\n";
1914 	cout << endl;
1915 	cout << "Tab Options:\n";
1916 	cout << "------------\n";
1917 	cout << "    default indent option\n";
1918 	cout << "    If no indentation option is set, the default\n";
1919 	cout << "    option of 4 spaces per indent will be used.\n";
1920 	cout << endl;
1921 	cout << "    --indent=spaces=#  OR  -s#\n";
1922 	cout << "    Indent using # spaces per indent. Not specifying #\n";
1923 	cout << "    will result in a default of 4 spaces per indent.\n";
1924 	cout << endl;
1925 	cout << "    --indent=tab  OR  --indent=tab=#  OR  -t  OR  -t#\n";
1926 	cout << "    Indent using tab characters, assuming that each\n";
1927 	cout << "    indent is # spaces long. Not specifying # will result\n";
1928 	cout << "    in a default assumption of 4 spaces per indent.\n";
1929 	cout << endl;
1930 	cout << "    --indent=force-tab=#  OR  -T#\n";
1931 	cout << "    Indent using tab characters, assuming that each\n";
1932 	cout << "    indent is # spaces long. Force tabs to be used in areas\n";
1933 	cout << "    AStyle would prefer to use spaces.\n";
1934 	cout << endl;
1935 	cout << "    --indent=force-tab-x=#  OR  -xT#\n";
1936 	cout << "    Allows the tab length to be set to a length that is different\n";
1937 	cout << "    from the indent length. This may cause the indentation to be\n";
1938 	cout << "    a mix of both spaces and tabs. This option sets the tab length.\n";
1939 	cout << endl;
1940 	cout << "Brace Modify Options:\n";
1941 	cout << "---------------------\n";
1942 	cout << "    --attach-namespaces  OR  -xn\n";
1943 	cout << "    Attach braces to a namespace statement.\n";
1944 	cout << endl;
1945 	cout << "    --attach-classes  OR  -xc\n";
1946 	cout << "    Attach braces to a class statement.\n";
1947 	cout << endl;
1948 	cout << "    --attach-inlines  OR  -xl\n";
1949 	cout << "    Attach braces to class inline function definitions.\n";
1950 	cout << endl;
1951 	cout << "    --attach-extern-c  OR  -xk\n";
1952 	cout << "    Attach braces to an extern \"C\" statement.\n";
1953 	cout << endl;
1954 	cout << "    --attach-closing-while  OR  -xV\n";
1955 	cout << "    Attach closing while of do-while to the closing brace.\n";
1956 	cout << endl;
1957 	cout << "Indentation Options:\n";
1958 	cout << "--------------------\n";
1959 	cout << "    --indent-classes  OR  -C\n";
1960 	cout << "    Indent 'class' blocks so that the entire block is indented.\n";
1961 	cout << endl;
1962 	cout << "    --indent-modifiers  OR  -xG\n";
1963 	cout << "    Indent 'class' access modifiers, 'public:', 'protected:' or\n";
1964 	cout << "    'private:', one half indent. The rest of the class is not\n";
1965 	cout << "    indented. \n";
1966 	cout << endl;
1967 	cout << "    --indent-switches  OR  -S\n";
1968 	cout << "    Indent 'switch' blocks, so that the inner 'case XXX:'\n";
1969 	cout << "    headers are indented in relation to the switch block.\n";
1970 	cout << endl;
1971 	cout << "    --indent-cases  OR  -K\n";
1972 	cout << "    Indent case blocks from the 'case XXX:' headers.\n";
1973 	cout << "    Case statements not enclosed in blocks are NOT indented.\n";
1974 	cout << endl;
1975 	cout << "    --indent-namespaces  OR  -N\n";
1976 	cout << "    Indent the contents of namespace blocks.\n";
1977 	cout << endl;
1978 	cout << "    --indent-after-parens  OR  -xU\n";
1979 	cout << "    Indent, instead of align, continuation lines following lines\n";
1980 	cout << "    that contain an opening paren '(' or an assignment '='. \n";
1981 	cout << endl;
1982 	cout << "    --indent-continuation=#  OR  -xt#\n";
1983 	cout << "    Indent continuation lines an additional # indents.\n";
1984 	cout << "    The valid values are 0 thru 4 indents.\n";
1985 	cout << "    The default value is 1 indent.\n";
1986 	cout << endl;
1987 	cout << "    --indent-labels  OR  -L\n";
1988 	cout << "    Indent labels so that they appear one indent less than\n";
1989 	cout << "    the current indentation level, rather than being\n";
1990 	cout << "    flushed completely to the left (which is the default).\n";
1991 	cout << endl;
1992 	cout << "    --indent-preproc-block  OR  -xW\n";
1993 	cout << "    Indent preprocessor blocks at brace level 0.\n";
1994 	cout << "    Without this option the preprocessor block is not indented.\n";
1995 	cout << endl;
1996 	cout << "    --indent-preproc-cond  OR  -xw\n";
1997 	cout << "    Indent preprocessor conditional statements #if/#else/#endif\n";
1998 	cout << "    to the same level as the source code.\n";
1999 	cout << endl;
2000 	cout << "    --indent-preproc-define  OR  -w\n";
2001 	cout << "    Indent multi-line preprocessor #define statements.\n";
2002 	cout << endl;
2003 	cout << "    --indent-col1-comments  OR  -Y\n";
2004 	cout << "    Indent line comments that start in column one.\n";
2005 	cout << endl;
2006 	cout << "    --min-conditional-indent=#  OR  -m#\n";
2007 	cout << "    Indent a minimal # spaces in a continuous conditional\n";
2008 	cout << "    belonging to a conditional header.\n";
2009 	cout << "    The valid values are:\n";
2010 	cout << "    0 - no minimal indent.\n";
2011 	cout << "    1 - indent at least one additional indent.\n";
2012 	cout << "    2 - indent at least two additional indents.\n";
2013 	cout << "    3 - indent at least one-half an additional indent.\n";
2014 	cout << "    The default value is 2, two additional indents.\n";
2015 	cout << endl;
2016 	cout << "    --max-continuation-indent=#  OR  -M#\n";
2017 	cout << "    Indent a maximal # spaces in a continuation line,\n";
2018 	cout << "    relative to the previous line.\n";
2019 	cout << "    The valid values are 40 thru 120.\n";
2020 	cout << "    The default value is 40.\n";
2021 	cout << endl;
2022 	cout << "Padding Options:\n";
2023 	cout << "----------------\n";
2024 	cout << "    --break-blocks  OR  -f\n";
2025 	cout << "    Insert empty lines around unrelated blocks, labels, classes, ...\n";
2026 	cout << endl;
2027 	cout << "    --break-blocks=all  OR  -F\n";
2028 	cout << "    Like --break-blocks, except also insert empty lines \n";
2029 	cout << "    around closing headers (e.g. 'else', 'catch', ...).\n";
2030 	cout << endl;
2031 	cout << "    --pad-oper  OR  -p\n";
2032 	cout << "    Insert space padding around operators.\n";
2033 	cout << endl;
2034 	cout << "    --pad-comma  OR  -xg\n";
2035 	cout << "    Insert space padding after commas.\n";
2036 	cout << endl;
2037 	cout << "    --pad-paren  OR  -P\n";
2038 	cout << "    Insert space padding around parenthesis on both the outside\n";
2039 	cout << "    and the inside.\n";
2040 	cout << endl;
2041 	cout << "    --pad-paren-out  OR  -d\n";
2042 	cout << "    Insert space padding around parenthesis on the outside only.\n";
2043 	cout << endl;
2044 	cout << "    --pad-first-paren-out  OR  -xd\n";
2045 	cout << "    Insert space padding around first parenthesis in a series on\n";
2046 	cout << "    the outside only.\n";
2047 	cout << endl;
2048 	cout << "    --pad-paren-in  OR  -D\n";
2049 	cout << "    Insert space padding around parenthesis on the inside only.\n";
2050 	cout << endl;
2051 	cout << "    --pad-header  OR  -H\n";
2052 	cout << "    Insert space padding after paren headers (e.g. 'if', 'for'...).\n";
2053 	cout << endl;
2054 	cout << "    --unpad-paren  OR  -U\n";
2055 	cout << "    Remove unnecessary space padding around parenthesis. This\n";
2056 	cout << "    can be used in combination with the 'pad' options above.\n";
2057 	cout << endl;
2058 	cout << "    --delete-empty-lines  OR  -xd\n";
2059 	cout << "    Delete empty lines within a function or method.\n";
2060 	cout << "    It will NOT delete lines added by the break-blocks options.\n";
2061 	cout << endl;
2062 	cout << "    --fill-empty-lines  OR  -E\n";
2063 	cout << "    Fill empty lines with the white space of their\n";
2064 	cout << "    previous lines.\n";
2065 	cout << endl;
2066 	cout << "    --align-pointer=type    OR  -k1\n";
2067 	cout << "    --align-pointer=middle  OR  -k2\n";
2068 	cout << "    --align-pointer=name    OR  -k3\n";
2069 	cout << "    Attach a pointer or reference operator (*, &, or ^) to either\n";
2070 	cout << "    the operator type (left), middle, or operator name (right).\n";
2071 	cout << "    To align the reference separately use --align-reference.\n";
2072 	cout << endl;
2073 	cout << "    --align-reference=none    OR  -W0\n";
2074 	cout << "    --align-reference=type    OR  -W1\n";
2075 	cout << "    --align-reference=middle  OR  -W2\n";
2076 	cout << "    --align-reference=name    OR  -W3\n";
2077 	cout << "    Attach a reference operator (&) to either\n";
2078 	cout << "    the operator type (left), middle, or operator name (right).\n";
2079 	cout << "    If not set, follow pointer alignment.\n";
2080 	cout << endl;
2081 	cout << "Formatting Options:\n";
2082 	cout << "-------------------\n";
2083 	cout << "    --break-closing-braces  OR  -y\n";
2084 	cout << "    Break braces before closing headers (e.g. 'else', 'catch', ...).\n";
2085 	cout << "    Use with --style=java, --style=kr, --style=stroustrup,\n";
2086 	cout << "    --style=linux, or --style=1tbs.\n";
2087 	cout << endl;
2088 	cout << "    --break-elseifs  OR  -e\n";
2089 	cout << "    Break 'else if()' statements into two different lines.\n";
2090 	cout << endl;
2091 	cout << "    --break-one-line-headers  OR  -xb\n";
2092 	cout << "    Break one line headers (e.g. 'if', 'while', 'else', ...) from a\n";
2093 	cout << "    statement residing on the same line.\n";
2094 	cout << endl;
2095 	cout << "    --add-braces  OR  -j\n";
2096 	cout << "    Add braces to unbraced one line conditional statements.\n";
2097 	cout << endl;
2098 	cout << "    --add-one-line-braces  OR  -J\n";
2099 	cout << "    Add one line braces to unbraced one line conditional\n";
2100 	cout << "    statements.\n";
2101 	cout << endl;
2102 	cout << "    --remove-braces  OR  -xj\n";
2103 	cout << "    Remove braces from a braced one line conditional statements.\n";
2104 	cout << endl;
2105 	cout << "    --break-return-type       OR  -xB\n";
2106 	cout << "    --break-return-type-decl  OR  -xD\n";
2107 	cout << "    Break the return type from the function name. Options are\n";
2108 	cout << "    for the function definitions and the function declarations.\n";
2109 	cout << endl;
2110 	cout << "    --attach-return-type       OR  -xf\n";
2111 	cout << "    --attach-return-type-decl  OR  -xh\n";
2112 	cout << "    Attach the return type to the function name. Options are\n";
2113 	cout << "    for the function definitions and the function declarations.\n";
2114 	cout << endl;
2115 	cout << "    --keep-one-line-blocks  OR  -O\n";
2116 	cout << "    Don't break blocks residing completely on one line.\n";
2117 	cout << endl;
2118 	cout << "    --keep-one-line-statements  OR  -o\n";
2119 	cout << "    Don't break lines containing multiple statements into\n";
2120 	cout << "    multiple single-statement lines.\n";
2121 	cout << endl;
2122 	cout << "    --convert-tabs  OR  -c\n";
2123 	cout << "    Convert tabs to the appropriate number of spaces.\n";
2124 	cout << endl;
2125 	cout << "    --close-templates  OR  -xy\n";
2126 	cout << "    Close ending angle brackets on template definitions.\n";
2127 	cout << endl;
2128 	cout << "    --remove-comment-prefix  OR  -xp\n";
2129 	cout << "    Remove the leading '*' prefix on multi-line comments and\n";
2130 	cout << "    indent the comment text one indent.\n";
2131 	cout << endl;
2132 	cout << "    --max-code-length=#    OR  -xC#\n";
2133 	cout << "    --break-after-logical  OR  -xL\n";
2134 	cout << "    max-code-length=# will break the line if it exceeds more than\n";
2135 	cout << "    # characters. The valid values are 50 thru 200.\n";
2136 	cout << "    If the line contains logical conditionals they will be placed\n";
2137 	cout << "    first on the new line. The option break-after-logical will\n";
2138 	cout << "    cause the logical conditional to be placed last on the\n";
2139 	cout << "    previous line.\n";
2140 	cout << endl;
2141 	cout << "    --mode=c\n";
2142 	cout << "    Indent a C or C++ source file (this is the default).\n";
2143 	cout << endl;
2144 	cout << "    --mode=java\n";
2145 	cout << "    Indent a Java source file.\n";
2146 	cout << endl;
2147 	cout << "    --mode=cs\n";
2148 	cout << "    Indent a C# source file.\n";
2149 	cout << endl;
2150 	cout << "Objective-C Options:\n";
2151 	cout << "--------------------\n";
2152 	cout << "    --pad-method-prefix  OR  -xQ\n";
2153 	cout << "    Insert space padding after the '-' or '+' Objective-C\n";
2154 	cout << "    method prefix.\n";
2155 	cout << endl;
2156 	cout << "    --unpad-method-prefix  OR  -xR\n";
2157 	cout << "    Remove all space padding after the '-' or '+' Objective-C\n";
2158 	cout << "    method prefix.\n";
2159 	cout << endl;
2160 	cout << "    --pad-return-type  OR  -xq\n";
2161 	cout << "    Insert space padding after the Objective-C return type.\n";
2162 	cout << endl;
2163 	cout << "    --unpad-return-type  OR  -xr\n";
2164 	cout << "    Remove all space padding after the Objective-C return type.\n";
2165 	cout << endl;
2166 	cout << "    --pad-param-type  OR  -xS\n";
2167 	cout << "    Insert space padding after the Objective-C return type.\n";
2168 	cout << endl;
2169 	cout << "    --unpad-param-type  OR  -xs\n";
2170 	cout << "    Remove all space padding after the Objective-C return type.\n";
2171 	cout << endl;
2172 	cout << "    --align-method-colon  OR  -xM\n";
2173 	cout << "    Align the colons in an Objective-C method definition.\n";
2174 	cout << endl;
2175 	cout << "    --pad-method-colon=none    OR  -xP\n";
2176 	cout << "    --pad-method-colon=all     OR  -xP1\n";
2177 	cout << "    --pad-method-colon=after   OR  -xP2\n";
2178 	cout << "    --pad-method-colon=before  OR  -xP3\n";
2179 	cout << "    Add or remove space padding before or after the colons in an\n";
2180 	cout << "    Objective-C method call.\n";
2181 	cout << endl;
2182 	cout << "Other Options:\n";
2183 	cout << "--------------\n";
2184 	cout << "    --suffix=####\n";
2185 	cout << "    Append the suffix #### instead of '.orig' to original filename.\n";
2186 	cout << endl;
2187 	cout << "    --suffix=none  OR  -n\n";
2188 	cout << "    Do not retain a backup of the original file.\n";
2189 	cout << endl;
2190 	cout << "    --recursive  OR  -r  OR  -R\n";
2191 	cout << "    Process subdirectories recursively.\n";
2192 	cout << endl;
2193 	cout << "    --dry-run\n";
2194 	cout << "    Perform a trial run with no changes made to check for formatting.\n";
2195 	cout << endl;
2196 	cout << "    --exclude=####\n";
2197 	cout << "    Specify a file or directory #### to be excluded from processing.\n";
2198 	cout << endl;
2199 	cout << "    --ignore-exclude-errors  OR  -i\n";
2200 	cout << "    Allow processing to continue if there are errors in the exclude=####\n";
2201 	cout << "    options. It will display the unmatched excludes.\n";
2202 	cout << endl;
2203 	cout << "    --ignore-exclude-errors-x  OR  -xi\n";
2204 	cout << "    Allow processing to continue if there are errors in the exclude=####\n";
2205 	cout << "    options. It will NOT display the unmatched excludes.\n";
2206 	cout << endl;
2207 	cout << "    --errors-to-stdout  OR  -X\n";
2208 	cout << "    Print errors and help information to standard-output rather than\n";
2209 	cout << "    to standard-error.\n";
2210 	cout << endl;
2211 	cout << "    --preserve-date  OR  -Z\n";
2212 	cout << "    Preserve the original file's date and time modified. The time\n";
2213 	cout << "     modified will be changed a few micro seconds to force a compile.\n";
2214 	cout << endl;
2215 	cout << "    --verbose  OR  -v\n";
2216 	cout << "    Verbose mode. Extra informational messages will be displayed.\n";
2217 	cout << endl;
2218 	cout << "    --formatted  OR  -Q\n";
2219 	cout << "    Formatted display mode. Display only the files that have been\n";
2220 	cout << "    formatted.\n";
2221 	cout << endl;
2222 	cout << "    --quiet  OR  -q\n";
2223 	cout << "    Quiet mode. Suppress all output except error messages.\n";
2224 	cout << endl;
2225 	cout << "    --lineend=windows  OR  -z1\n";
2226 	cout << "    --lineend=linux    OR  -z2\n";
2227 	cout << "    --lineend=macold   OR  -z3\n";
2228 	cout << "    Force use of the specified line end style. Valid options\n";
2229 	cout << "    are windows (CRLF), linux (LF), and macold (CR).\n";
2230 	cout << endl;
2231 	cout << "Command Line Only:\n";
2232 	cout << "------------------\n";
2233 	cout << "    --options=####\n";
2234 	cout << "    --options=none\n";
2235 	cout << "    Specify a default option file #### to read and use.\n";
2236 	cout << "    It must contain a file path and a file name.\n";
2237 	cout << "    'none' disables the default option file.\n";
2238 	cout << endl;
2239 	cout << "    --project\n";
2240 	cout << "    --project=####\n";
2241 	cout << "    --project=none\n";
2242 	cout << "    Specify a project option file #### to read and use.\n";
2243 	cout << "    It must contain a file name only, without a directory path.\n";
2244 	cout << "    The file should be included in the project top-level directory.\n";
2245 	cout << "    The default file name is .astylerc or _astylerc.\n";
2246 	cout << "    'none' disables the project or environment variable file.\n";
2247 	cout << endl;
2248 	cout << "    --ascii  OR  -I\n";
2249 	cout << "    The displayed output will be ascii characters only.\n";
2250 	cout << endl;
2251 	cout << "    --version  OR  -V\n";
2252 	cout << "    Print version number.\n";
2253 	cout << endl;
2254 	cout << "    --help  OR  -h  OR  -?\n";
2255 	cout << "    Print this help message.\n";
2256 	cout << endl;
2257 	cout << "    --html  OR  -!\n";
2258 	cout << "    Open the HTML help file \"astyle.html\" in the default browser.\n";
2259 	cout << "    The documentation must be installed in the standard install path.\n";
2260 	cout << endl;
2261 	cout << "    --html=####\n";
2262 	cout << "    Open a HTML help file in the default browser using the file path\n";
2263 	cout << "    ####. The path may include a directory path and a file name, or a\n";
2264 	cout << "    file name only. Paths containing spaces must be enclosed in quotes.\n";
2265 	cout << endl;
2266 	cout << "    --stdin=####\n";
2267 	cout << "    Use the file path #### as input to single file formatting.\n";
2268 	cout << "    This is a replacement for redirection.\n";
2269 	cout << endl;
2270 	cout << "    --stdout=####\n";
2271 	cout << "    Use the file path #### as output from single file formatting.\n";
2272 	cout << "    This is a replacement for redirection.\n";
2273 	cout << endl;
2274 	cout << endl;
2275 }
2276 
2277 /**
2278  * Process files in the fileNameVector.
2279  */
processFiles()2280 void ASConsole::processFiles()
2281 {
2282 	if (isVerbose)
2283 		printVerboseHeader();
2284 
2285 	clock_t startTime = clock();     // start time of file formatting
2286 
2287 	// loop thru input fileNameVector and process the files
2288 	for (size_t i = 0; i < fileNameVector.size(); i++)
2289 	{
2290 		getFilePaths(fileNameVector[i]);
2291 
2292 		// loop thru fileName vector formatting the files
2293 		for (size_t j = 0; j < fileName.size(); j++)
2294 			formatFile(fileName[j]);
2295 	}
2296 
2297 	// files are processed, display stats
2298 	if (isVerbose)
2299 		printVerboseStats(startTime);
2300 }
2301 
2302 // process options from the command line and option files
2303 // build the vectors fileNameVector, excludeVector, optionsVector,
2304 // projectOptionsVector and fileOptionsVector
processOptions(const vector<string> & argvOptions)2305 void ASConsole::processOptions(const vector<string>& argvOptions)
2306 {
2307 	string arg;
2308 	bool ok = true;
2309 	bool optionFileRequired = false;
2310 	bool shouldParseOptionFile = true;
2311 	bool projectOptionFileRequired = false;
2312 	bool shouldParseProjectOptionFile = true;
2313 	string projectOptionArg;		// save for display
2314 
2315 	// get command line options
2316 	for (size_t i = 0; i < argvOptions.size(); i++)
2317 	{
2318 		arg = argvOptions[i];
2319 
2320 		if (isOption(arg, "-I")
2321 		        || isOption(arg, "--ascii"))
2322 		{
2323 			useAscii = true;
2324 			setlocale(LC_ALL, "C");		// use English decimal indicator
2325 			localizer.setLanguageFromName("en");
2326 		}
2327 		else if (isOption(arg, "--options=none"))
2328 		{
2329 			optionFileRequired = false;
2330 			shouldParseOptionFile = false;
2331 			optionFileName = "";
2332 		}
2333 		else if (isParamOption(arg, "--options="))
2334 		{
2335 			optionFileName = getParam(arg, "--options=");
2336 			standardizePath(optionFileName);
2337 			optionFileName = getFullPathName(optionFileName);
2338 			optionFileRequired = true;
2339 		}
2340 		else if (isOption(arg, "--project=none"))
2341 		{
2342 			projectOptionFileRequired = false;
2343 			shouldParseProjectOptionFile = false;
2344 			setProjectOptionFileName("");
2345 		}
2346 		else if (isParamOption(arg, "--project="))
2347 		{
2348 			projectOptionFileName = getParam(arg, "--project=");
2349 			standardizePath(projectOptionFileName);
2350 			projectOptionFileRequired = true;
2351 			shouldParseProjectOptionFile = false;
2352 			projectOptionArg = projectOptionFileName;
2353 		}
2354 		else if (isOption(arg, "--project"))
2355 		{
2356 			projectOptionFileName = ".astylerc";
2357 			projectOptionFileRequired = true;
2358 			shouldParseProjectOptionFile = false;
2359 			projectOptionArg = projectOptionFileName;
2360 		}
2361 		else if (isOption(arg, "-h")
2362 		         || isOption(arg, "--help")
2363 		         || isOption(arg, "-?"))
2364 		{
2365 			printHelp();
2366 			exit(EXIT_SUCCESS);
2367 		}
2368 		else if (isOption(arg, "-!")
2369 		         || isOption(arg, "--html"))
2370 		{
2371 			launchDefaultBrowser();
2372 			exit(EXIT_SUCCESS);
2373 		}
2374 		else if (isParamOption(arg, "--html="))
2375 		{
2376 			string htmlFilePath = getParam(arg, "--html=");
2377 			launchDefaultBrowser(htmlFilePath.c_str());
2378 			exit(EXIT_SUCCESS);
2379 		}
2380 		else if (isOption(arg, "-V")
2381 		         || isOption(arg, "--version"))
2382 		{
2383 			printf("Artistic Style Version %s\n", g_version);
2384 			exit(EXIT_SUCCESS);
2385 		}
2386 		else if (isParamOption(arg, "--stdin="))
2387 		{
2388 			string path = getParam(arg, "--stdin=");
2389 			standardizePath(path);
2390 			setStdPathIn(path);
2391 		}
2392 		else if (isParamOption(arg, "--stdout="))
2393 		{
2394 			string path = getParam(arg, "--stdout=");
2395 			standardizePath(path);
2396 			setStdPathOut(path);
2397 		}
2398 		else if (arg[0] == '-')
2399 		{
2400 			optionsVector.emplace_back(arg);
2401 		}
2402 		else // file-name
2403 		{
2404 			standardizePath(arg);
2405 			fileNameVector.emplace_back(arg);
2406 		}
2407 	}
2408 
2409 	// get option file path and name
2410 	if (shouldParseOptionFile)
2411 	{
2412 		if (optionFileName.empty())
2413 		{
2414 			char* env = getenv("ARTISTIC_STYLE_OPTIONS");
2415 			if (env != nullptr)
2416 			{
2417 				setOptionFileName(env);
2418 				standardizePath(optionFileName);
2419 				optionFileName = getFullPathName(optionFileName);
2420 			}
2421 		}
2422 		// for Linux
2423 		if (optionFileName.empty())
2424 		{
2425 			char* env = getenv("HOME");
2426 			if (env != nullptr)
2427 			{
2428 				string name = string(env) + "/.astylerc";
2429 				if (fileExists(name.c_str()))
2430 					setOptionFileName(name);
2431 			}
2432 		}
2433 		// for Windows
2434 		if (optionFileName.empty())
2435 		{
2436 			char* env = getenv("APPDATA");
2437 			if (env != nullptr)
2438 			{
2439 				string name = string(env) + "\\astylerc";
2440 				if (fileExists(name.c_str()))
2441 					setOptionFileName(name);
2442 			}
2443 		}
2444 		// for Windows
2445 		// NOTE: depreciated with release 3.1, remove when appropriate
2446 		// there is NO test data for this option
2447 		if (optionFileName.empty())
2448 		{
2449 			char* env = getenv("USERPROFILE");
2450 			if (env != nullptr)
2451 			{
2452 				string name = string(env) + "\\astylerc";
2453 				if (fileExists(name.c_str()))
2454 					setOptionFileName(name);
2455 			}
2456 		}
2457 	}
2458 
2459 	// find project option file
2460 	if (projectOptionFileRequired)
2461 	{
2462 		string optfilepath = findProjectOptionFilePath(projectOptionFileName);
2463 		if (optfilepath.empty() || projectOptionArg.empty())
2464 			error(_("Cannot open project option file"), projectOptionArg.c_str());
2465 		standardizePath(optfilepath);
2466 		setProjectOptionFileName(optfilepath);
2467 	}
2468 	if (shouldParseProjectOptionFile)
2469 	{
2470 		char* env = getenv("ARTISTIC_STYLE_PROJECT_OPTIONS");
2471 		if (env != nullptr)
2472 		{
2473 			string optfilepath = findProjectOptionFilePath(env);
2474 			standardizePath(optfilepath);
2475 			setProjectOptionFileName(optfilepath);
2476 		}
2477 	}
2478 
2479 	ASOptions options(formatter, *this);
2480 	if (!optionFileName.empty())
2481 	{
2482 		stringstream optionsIn;
2483 		if (!fileExists(optionFileName.c_str()))
2484 			error(_("Cannot open default option file"), optionFileName.c_str());
2485 		FileEncoding encoding = readFile(optionFileName, optionsIn);
2486 		// bypass a BOM, all BOMs have been converted to utf-8
2487 		if (encoding == UTF_8BOM || encoding == UTF_16LE || encoding == UTF_16BE)
2488 		{
2489 			char buf[4];
2490 			optionsIn.get(buf, 4);
2491 			assert(strcmp(buf, "\xEF\xBB\xBF") == 0);
2492 		}
2493 		options.importOptions(optionsIn, fileOptionsVector);
2494 		ok = options.parseOptions(fileOptionsVector,
2495 		                          string(_("Invalid default options:")));
2496 	}
2497 	else if (optionFileRequired)
2498 		error(_("Cannot open default option file"), optionFileName.c_str());
2499 
2500 	if (!ok)
2501 	{
2502 		(*errorStream) << options.getOptionErrors();
2503 		(*errorStream) << _("For help on options type 'astyle -h'") << endl;
2504 		error();
2505 	}
2506 
2507 	if (!projectOptionFileName.empty())
2508 	{
2509 		stringstream projectOptionsIn;
2510 		if (!fileExists(projectOptionFileName.c_str()))
2511 			error(_("Cannot open project option file"), projectOptionFileName.c_str());
2512 		FileEncoding encoding = readFile(projectOptionFileName, projectOptionsIn);
2513 		// bypass a BOM, all BOMs have been converted to utf-8
2514 		if (encoding == UTF_8BOM || encoding == UTF_16LE || encoding == UTF_16BE)
2515 		{
2516 			char buf[4];
2517 			projectOptionsIn.get(buf, 4);
2518 			assert(strcmp(buf, "\xEF\xBB\xBF") == 0);
2519 		}
2520 		options.importOptions(projectOptionsIn, projectOptionsVector);
2521 		ok = options.parseOptions(projectOptionsVector,
2522 		                          string(_("Invalid project options:")));
2523 	}
2524 
2525 	if (!ok)
2526 	{
2527 		(*errorStream) << options.getOptionErrors();
2528 		(*errorStream) << _("For help on options type 'astyle -h'") << endl;
2529 		error();
2530 	}
2531 
2532 	// parse the command line options vector for errors
2533 	ok = options.parseOptions(optionsVector,
2534 	                          string(_("Invalid command line options:")));
2535 	if (!ok)
2536 	{
2537 		(*errorStream) << options.getOptionErrors();
2538 		(*errorStream) << _("For help on options type 'astyle -h'") << endl;
2539 		error();
2540 	}
2541 }
2542 
2543 // remove a file and check for an error
removeFile(const char * fileName_,const char * errMsg) const2544 void ASConsole::removeFile(const char* fileName_, const char* errMsg) const
2545 {
2546 	if (remove(fileName_) != 0)
2547 	{
2548 		if (errno == ENOENT)        // no file is OK
2549 			errno = 0;
2550 		if (errno)
2551 		{
2552 			perror("errno message");
2553 			error(errMsg, fileName_);
2554 		}
2555 	}
2556 }
2557 
2558 // rename a file and check for an error
renameFile(const char * oldFileName,const char * newFileName,const char * errMsg) const2559 void ASConsole::renameFile(const char* oldFileName, const char* newFileName, const char* errMsg) const
2560 {
2561 	int result = rename(oldFileName, newFileName);
2562 	if (result != 0)
2563 	{
2564 		// if file still exists the remove needs more time - retry
2565 		if (errno == EEXIST)
2566 		{
2567 			errno = 0;
2568 			waitForRemove(newFileName);
2569 			result = rename(oldFileName, newFileName);
2570 		}
2571 		if (result != 0)
2572 		{
2573 			perror("errno message");
2574 			error(errMsg, oldFileName);
2575 		}
2576 	}
2577 }
2578 
2579 // make sure file separators are correct type (Windows or Linux)
2580 // remove ending file separator
2581 // remove beginning file separator if requested and NOT a complete file path
standardizePath(string & path,bool removeBeginningSeparator) const2582 void ASConsole::standardizePath(string& path, bool removeBeginningSeparator /*false*/) const
2583 {
2584 #ifdef __VMS
2585 	struct FAB fab;
2586 	struct NAML naml;
2587 	char less[NAML$C_MAXRSS];
2588 	char sess[NAM$C_MAXRSS];
2589 	int r0_status;
2590 
2591 	// If we are on a VMS system, translate VMS style filenames to unix
2592 	// style.
2593 	fab = cc$rms_fab;
2594 	fab.fab$l_fna = (char*) -1;
2595 	fab.fab$b_fns = 0;
2596 	fab.fab$l_naml = &naml;
2597 	naml = cc$rms_naml;
2598 	strcpy(sess, path.c_str());
2599 	naml.naml$l_long_filename = (char*) sess;
2600 	naml.naml$l_long_filename_size = path.length();
2601 	naml.naml$l_long_expand = less;
2602 	naml.naml$l_long_expand_alloc = sizeof(less);
2603 	naml.naml$l_esa = sess;
2604 	naml.naml$b_ess = sizeof(sess);
2605 	naml.naml$v_no_short_upcase = 1;
2606 	r0_status = sys$parse(&fab);
2607 	if (r0_status == RMS$_SYN)
2608 	{
2609 		error("File syntax error", path.c_str());
2610 	}
2611 	else
2612 	{
2613 		if (!$VMS_STATUS_SUCCESS(r0_status))
2614 		{
2615 			(void) lib$signal(r0_status);
2616 		}
2617 	}
2618 	less[naml.naml$l_long_expand_size - naml.naml$b_ver] = '\0';
2619 	sess[naml.naml$b_esl - naml.naml$b_ver] = '\0';
2620 	if (naml.naml$l_long_expand_size > naml.naml$b_esl)
2621 	{
2622 		path = decc$translate_vms(less);
2623 	}
2624 	else
2625 	{
2626 		path = decc$translate_vms(sess);
2627 	}
2628 #endif /* __VMS */
2629 
2630 	// make sure separators are correct type (Windows or Linux)
2631 	for (size_t i = 0; i < path.length(); i++)
2632 	{
2633 		i = path.find_first_of("/\\", i);
2634 		if (i == string::npos)
2635 			break;
2636 		path[i] = g_fileSeparator;
2637 	}
2638 	// remove beginning separator if requested
2639 	if (removeBeginningSeparator && (path[0] == g_fileSeparator))
2640 		path.erase(0, 1);
2641 }
2642 
printMsg(const char * msg,const string & data) const2643 void ASConsole::printMsg(const char* msg, const string& data) const
2644 {
2645 	if (isQuiet)
2646 		return;
2647 	printf(msg, data.c_str());
2648 }
2649 
printSeparatingLine() const2650 void ASConsole::printSeparatingLine() const
2651 {
2652 	string line;
2653 	for (size_t i = 0; i < 60; i++)
2654 		line.append("-");
2655 	printMsg("%s\n", line);
2656 }
2657 
printVerboseHeader() const2658 void ASConsole::printVerboseHeader() const
2659 {
2660 	assert(isVerbose);
2661 	if (isQuiet)
2662 		return;
2663 	// get the date
2664 	time_t lt;
2665 	char str[20];
2666 	lt = time(nullptr);
2667 	struct tm* ptr = localtime(&lt);
2668 	strftime(str, 20, "%x", ptr);
2669 	// print the header
2670 	// 60 is the length of the separator in printSeparatingLine()
2671 	string header = "Artistic Style " + string(g_version);
2672 	size_t numSpaces = 60 - header.length() - strlen(str);
2673 	header.append(numSpaces, ' ');
2674 	header.append(str);
2675 	header.append("\n");
2676 	printf("%s", header.c_str());
2677 	// print option files
2678 	if (!optionFileName.empty())
2679 		printf(_("Default option file  %s\n"), optionFileName.c_str());
2680 	// NOTE: depreciated with release 3.1, remove when appropriate
2681 	if (!optionFileName.empty())
2682 	{
2683 		char* env = getenv("USERPROFILE");
2684 		if (env != nullptr && optionFileName == string(env) + "\\astylerc")
2685 			printf("The above option file has been DEPRECIATED\n");
2686 	}
2687 	// end depreciated
2688 	if (!projectOptionFileName.empty())
2689 		printf(_("Project option file  %s\n"), projectOptionFileName.c_str());
2690 }
2691 
printVerboseStats(clock_t startTime) const2692 void ASConsole::printVerboseStats(clock_t startTime) const
2693 {
2694 	assert(isVerbose);
2695 	if (isQuiet)
2696 		return;
2697 	if (hasWildcard)
2698 		printSeparatingLine();
2699 	string formatted = getNumberFormat(filesFormatted);
2700 	string unchanged = getNumberFormat(filesUnchanged);
2701 	printf(_(" %s formatted   %s unchanged   "), formatted.c_str(), unchanged.c_str());
2702 
2703 	// show processing time
2704 	clock_t stopTime = clock();
2705 	double secs = (stopTime - startTime) / double(CLOCKS_PER_SEC);
2706 	if (secs < 60)
2707 	{
2708 		if (secs < 2.0)
2709 			printf("%.2f", secs);
2710 		else if (secs < 20.0)
2711 			printf("%.1f", secs);
2712 		else
2713 			printf("%.0f", secs);
2714 		printf("%s", _(" seconds   "));
2715 	}
2716 	else
2717 	{
2718 		// show minutes and seconds if time is greater than one minute
2719 		int min = (int) secs / 60;
2720 		secs -= min * 60;
2721 		int minsec = int(secs + .5);
2722 		printf(_("%d min %d sec   "), min, minsec);
2723 	}
2724 
2725 	string lines = getNumberFormat(linesOut);
2726 	printf(_("%s lines\n"), lines.c_str());
2727 	printf("\n");
2728 }
2729 
sleep(int seconds) const2730 void ASConsole::sleep(int seconds) const
2731 {
2732 	clock_t endwait;
2733 	endwait = clock_t(clock() + seconds * CLOCKS_PER_SEC);
2734 	while (clock() < endwait) {}
2735 }
2736 
stringEndsWith(const string & str,const string & suffix) const2737 bool ASConsole::stringEndsWith(const string& str, const string& suffix) const
2738 {
2739 	int strIndex = (int) str.length() - 1;
2740 	int suffixIndex = (int) suffix.length() - 1;
2741 
2742 	while (strIndex >= 0 && suffixIndex >= 0)
2743 	{
2744 		if (tolower(str[strIndex]) != tolower(suffix[suffixIndex]))
2745 			return false;
2746 
2747 		--strIndex;
2748 		--suffixIndex;
2749 	}
2750 	// suffix longer than string
2751 	if (strIndex < 0 && suffixIndex >= 0)
2752 		return false;
2753 	return true;
2754 }
2755 
updateExcludeVector(const string & suffixParam)2756 void ASConsole::updateExcludeVector(const string& suffixParam)
2757 {
2758 	excludeVector.emplace_back(suffixParam);
2759 	standardizePath(excludeVector.back(), true);
2760 	excludeHitsVector.push_back(false);
2761 }
2762 
waitForRemove(const char * newFileName) const2763 int ASConsole::waitForRemove(const char* newFileName) const
2764 {
2765 	struct stat stBuf;
2766 	int seconds;
2767 	// sleep a max of 20 seconds for the remove
2768 	for (seconds = 1; seconds <= 20; seconds++)
2769 	{
2770 		sleep(1);
2771 		if (stat(newFileName, &stBuf) != 0)
2772 			break;
2773 	}
2774 	errno = 0;
2775 	return seconds;
2776 }
2777 
2778 // From The Code Project http://www.codeproject.com/string/wildcmp.asp
2779 // Written by Jack Handy - jakkhandy@hotmail.com
2780 // Modified to compare case insensitive for Windows
wildcmp(const char * wild,const char * data) const2781 int ASConsole::wildcmp(const char* wild, const char* data) const
2782 {
2783 	const char* cp = nullptr, *mp = nullptr;
2784 	bool cmpval;
2785 
2786 	while ((*data) && (*wild != '*'))
2787 	{
2788 		if (!g_isCaseSensitive)
2789 			cmpval = (tolower(*wild) != tolower(*data)) && (*wild != '?');
2790 		else
2791 			cmpval = (*wild != *data) && (*wild != '?');
2792 
2793 		if (cmpval)
2794 		{
2795 			return 0;
2796 		}
2797 		wild++;
2798 		data++;
2799 	}
2800 
2801 	while (*data)
2802 	{
2803 		if (*wild == '*')
2804 		{
2805 			if (!*++wild)
2806 			{
2807 				return 1;
2808 			}
2809 			mp = wild;
2810 			cp = data + 1;
2811 		}
2812 		else
2813 		{
2814 			if (!g_isCaseSensitive)
2815 				cmpval = (tolower(*wild) == tolower(*data) || (*wild == '?'));
2816 			else
2817 				cmpval = (*wild == *data) || (*wild == '?');
2818 
2819 			if (cmpval)
2820 			{
2821 				wild++;
2822 				data++;
2823 			}
2824 			else
2825 			{
2826 				wild = mp;
2827 				data = cp++;
2828 			}
2829 		}
2830 	}
2831 
2832 	while (*wild == '*')
2833 	{
2834 		wild++;
2835 	}
2836 	return !*wild;
2837 }
2838 
writeFile(const string & fileName_,FileEncoding encoding,ostringstream & out) const2839 void ASConsole::writeFile(const string& fileName_, FileEncoding encoding, ostringstream& out) const
2840 {
2841 	// save date accessed and date modified of original file
2842 	struct stat stBuf;
2843 	bool statErr = false;
2844 	if (stat(fileName_.c_str(), &stBuf) == -1)
2845 		statErr = true;
2846 
2847 	// create a backup
2848 	if (!noBackup)
2849 	{
2850 		string origFileName = fileName_ + origSuffix;
2851 		removeFile(origFileName.c_str(), "Cannot remove pre-existing backup file");
2852 		renameFile(fileName_.c_str(), origFileName.c_str(), "Cannot create backup file");
2853 	}
2854 
2855 	// write the output file
2856 	ofstream fout(fileName_.c_str(), ios::binary | ios::trunc);
2857 	if (!fout)
2858 		error("Cannot open output file", fileName_.c_str());
2859 	if (encoding == UTF_16LE || encoding == UTF_16BE)
2860 	{
2861 		// convert utf-8 to utf-16
2862 		bool isBigEndian = (encoding == UTF_16BE);
2863 		size_t utf16Size = encode.utf16LengthFromUtf8(out.str().c_str(), out.str().length());
2864 		char* utf16Out = new char[utf16Size];
2865 		size_t utf16Len = encode.utf8ToUtf16(const_cast<char*>(out.str().c_str()),
2866 		                                     out.str().length(), isBigEndian, utf16Out);
2867 		assert(utf16Len <= utf16Size);
2868 		fout << string(utf16Out, utf16Len);
2869 		delete[] utf16Out;
2870 	}
2871 	else
2872 		fout << out.str();
2873 
2874 	fout.close();
2875 
2876 	// change date modified to original file date
2877 	// Embarcadero must be linked with cw32mt not cw32
2878 	if (preserveDate)
2879 	{
2880 		if (!statErr)
2881 		{
2882 			struct utimbuf outBuf;
2883 			outBuf.actime = stBuf.st_atime;
2884 			// add ticks so 'make' will recognize a change
2885 			// Visual Studio 2008 needs more than 1
2886 			outBuf.modtime = stBuf.st_mtime + 10;
2887 			if (utime(fileName_.c_str(), &outBuf) == -1)
2888 				statErr = true;
2889 		}
2890 		if (statErr)
2891 		{
2892 			perror("errno message");
2893 			(*errorStream) << "*********  Cannot preserve file date" << endl;
2894 		}
2895 	}
2896 }
2897 
2898 #else	// ASTYLE_LIB
2899 
2900 //-----------------------------------------------------------------------------
2901 // ASLibrary class
2902 // used by shared object (DLL) calls
2903 //-----------------------------------------------------------------------------
2904 
formatUtf16(const char16_t * pSourceIn,const char16_t * pOptions,fpError fpErrorHandler,fpAlloc fpMemoryAlloc) const2905 char16_t* ASLibrary::formatUtf16(const char16_t* pSourceIn,		// the source to be formatted
2906                                  const char16_t* pOptions,		// AStyle options
2907                                  fpError fpErrorHandler,		// error handler function
2908                                  fpAlloc fpMemoryAlloc) const	// memory allocation function)
2909 {
2910 	const char* utf8In = convertUtf16ToUtf8(pSourceIn);
2911 	if (utf8In == nullptr)
2912 	{
2913 		fpErrorHandler(121, "Cannot convert input utf-16 to utf-8.");
2914 		return nullptr;
2915 	}
2916 	const char* utf8Options = convertUtf16ToUtf8(pOptions);
2917 	if (utf8Options == nullptr)
2918 	{
2919 		delete[] utf8In;
2920 		fpErrorHandler(122, "Cannot convert options utf-16 to utf-8.");
2921 		return nullptr;
2922 	}
2923 	// call the Artistic Style formatting function
2924 	// cannot use the callers memory allocation here
2925 	char* utf8Out = AStyleMain(utf8In,
2926 	                           utf8Options,
2927 	                           fpErrorHandler,
2928 	                           ASLibrary::tempMemoryAllocation);
2929 	// finished with these
2930 	delete[] utf8In;
2931 	delete[] utf8Options;
2932 	utf8In = nullptr;
2933 	utf8Options = nullptr;
2934 	// AStyle error has already been sent
2935 	if (utf8Out == nullptr)
2936 		return nullptr;
2937 	// convert text to wide char and return it
2938 	char16_t* utf16Out = convertUtf8ToUtf16(utf8Out, fpMemoryAlloc);
2939 	delete[] utf8Out;
2940 	utf8Out = nullptr;
2941 	if (utf16Out == nullptr)
2942 	{
2943 		fpErrorHandler(123, "Cannot convert output utf-8 to utf-16.");
2944 		return nullptr;
2945 	}
2946 	return utf16Out;
2947 }
2948 
2949 // STATIC method to allocate temporary memory for AStyle formatting.
2950 // The data will be converted before being returned to the calling program.
tempMemoryAllocation(unsigned long memoryNeeded)2951 char* STDCALL ASLibrary::tempMemoryAllocation(unsigned long memoryNeeded)
2952 {
2953 	char* buffer = new (nothrow) char[memoryNeeded];
2954 	return buffer;
2955 }
2956 
2957 /**
2958  * Convert utf-8 strings to utf16 strings.
2959  * Memory is allocated by the calling program memory allocation function.
2960  * The calling function must check for errors.
2961  */
convertUtf8ToUtf16(const char * utf8In,fpAlloc fpMemoryAlloc) const2962 char16_t* ASLibrary::convertUtf8ToUtf16(const char* utf8In, fpAlloc fpMemoryAlloc) const
2963 {
2964 	if (utf8In == nullptr)
2965 		return nullptr;
2966 	char* data = const_cast<char*>(utf8In);
2967 	size_t dataSize = strlen(utf8In);
2968 	bool isBigEndian = encode.getBigEndian();
2969 	// return size is in number of CHARs, not char16_t
2970 	size_t utf16Size = (encode.utf16LengthFromUtf8(data, dataSize) + sizeof(char16_t));
2971 	char* utf16Out = fpMemoryAlloc((long) utf16Size);
2972 	if (utf16Out == nullptr)
2973 		return nullptr;
2974 #ifdef NDEBUG
2975 	encode.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
2976 #else
2977 	size_t utf16Len = encode.utf8ToUtf16(data, dataSize + 1, isBigEndian, utf16Out);
2978 	assert(utf16Len == utf16Size);
2979 #endif
2980 	assert(utf16Size == (encode.utf16len(reinterpret_cast<char16_t*>(utf16Out)) + 1) * sizeof(char16_t));
2981 	return reinterpret_cast<char16_t*>(utf16Out);
2982 }
2983 
2984 /**
2985  * Convert utf16 strings to utf-8.
2986  * The calling function must check for errors and delete the
2987  * allocated memory.
2988  */
convertUtf16ToUtf8(const char16_t * utf16In) const2989 char* ASLibrary::convertUtf16ToUtf8(const char16_t* utf16In) const
2990 {
2991 	if (utf16In == nullptr)
2992 		return nullptr;
2993 	char* data = reinterpret_cast<char*>(const_cast<char16_t*>(utf16In));
2994 	// size must be in chars
2995 	size_t dataSize = encode.utf16len(utf16In) * sizeof(char16_t);
2996 	bool isBigEndian = encode.getBigEndian();
2997 	size_t utf8Size = encode.utf8LengthFromUtf16(data, dataSize, isBigEndian) + 1;
2998 	char* utf8Out = new (nothrow) char[utf8Size];
2999 	if (utf8Out == nullptr)
3000 		return nullptr;
3001 #ifdef NDEBUG
3002 	encode.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
3003 #else
3004 	size_t utf8Len = encode.utf16ToUtf8(data, dataSize + 1, isBigEndian, true, utf8Out);
3005 	assert(utf8Len == utf8Size);
3006 #endif
3007 	assert(utf8Size == strlen(utf8Out) + 1);
3008 	return utf8Out;
3009 }
3010 
3011 #endif	// ASTYLE_LIB
3012 
3013 //-----------------------------------------------------------------------------
3014 // ASOptions class
3015 // used by both console and library builds
3016 //-----------------------------------------------------------------------------
3017 
3018 #ifdef ASTYLE_LIB
ASOptions(ASFormatter & formatterArg)3019 ASOptions::ASOptions(ASFormatter& formatterArg)
3020 	: formatter(formatterArg)
3021 { }
3022 #else
ASOptions(ASFormatter & formatterArg,ASConsole & consoleArg)3023 ASOptions::ASOptions(ASFormatter& formatterArg, ASConsole& consoleArg)
3024 	: formatter(formatterArg), console(consoleArg)
3025 { }
3026 #endif
3027 
3028 /**
3029  * parse the options vector
3030  * optionsVector can be either a fileOptionsVector (option file),
3031  * a projectOptionsVector (project option file),
3032  * or an optionsVector (command line)
3033  *
3034  * @return        true if no errors, false if errors
3035  */
parseOptions(vector<string> & optionsVector,const string & errorInfo)3036 bool ASOptions::parseOptions(vector<string>& optionsVector, const string& errorInfo)
3037 {
3038 	vector<string>::iterator option;
3039 	string arg, subArg;
3040 	optionErrors.clear();
3041 
3042 	for (option = optionsVector.begin(); option != optionsVector.end(); ++option)
3043 	{
3044 		arg = *option;
3045 
3046 		if (arg.compare(0, 2, "--") == 0)
3047 			parseOption(arg.substr(2), errorInfo);
3048 		else if (arg[0] == '-')
3049 		{
3050 			size_t i;
3051 
3052 			for (i = 1; i < arg.length(); ++i)
3053 			{
3054 				if (i > 1
3055 				        && isalpha((unsigned char) arg[i])
3056 				        && arg[i - 1] != 'x')
3057 				{
3058 					// parse the previous option in subArg
3059 					parseOption(subArg, errorInfo);
3060 					subArg = "";
3061 				}
3062 				// append the current option to subArg
3063 				subArg.append(1, arg[i]);
3064 			}
3065 			// parse the last option
3066 			parseOption(subArg, errorInfo);
3067 			subArg = "";
3068 		}
3069 		else
3070 		{
3071 			parseOption(arg, errorInfo);
3072 			subArg = "";
3073 		}
3074 	}
3075 	if (optionErrors.str().length() > 0)
3076 		return false;
3077 	return true;
3078 }
3079 
parseOption(const string & arg,const string & errorInfo)3080 void ASOptions::parseOption(const string& arg, const string& errorInfo)
3081 {
3082 	if (isOption(arg, "A1", "style=allman") || isOption(arg, "style=bsd") || isOption(arg, "style=break"))
3083 	{
3084 		formatter.setFormattingStyle(STYLE_ALLMAN);
3085 	}
3086 	else if (isOption(arg, "A2", "style=java") || isOption(arg, "style=attach"))
3087 	{
3088 		formatter.setFormattingStyle(STYLE_JAVA);
3089 	}
3090 	else if (isOption(arg, "A3", "style=k&r") || isOption(arg, "style=kr") || isOption(arg, "style=k/r"))
3091 	{
3092 		formatter.setFormattingStyle(STYLE_KR);
3093 	}
3094 	else if (isOption(arg, "A4", "style=stroustrup"))
3095 	{
3096 		formatter.setFormattingStyle(STYLE_STROUSTRUP);
3097 	}
3098 	else if (isOption(arg, "A5", "style=whitesmith"))
3099 	{
3100 		formatter.setFormattingStyle(STYLE_WHITESMITH);
3101 	}
3102 	else if (isOption(arg, "A15", "style=vtk"))
3103 	{
3104 		formatter.setFormattingStyle(STYLE_VTK);
3105 	}
3106 	else if (isOption(arg, "A6", "style=ratliff") || isOption(arg, "style=banner"))
3107 	{
3108 		formatter.setFormattingStyle(STYLE_RATLIFF);
3109 	}
3110 	else if (isOption(arg, "A7", "style=gnu"))
3111 	{
3112 		formatter.setFormattingStyle(STYLE_GNU);
3113 	}
3114 	else if (isOption(arg, "A8", "style=linux") || isOption(arg, "style=knf"))
3115 	{
3116 		formatter.setFormattingStyle(STYLE_LINUX);
3117 	}
3118 	else if (isOption(arg, "A9", "style=horstmann") || isOption(arg, "style=run-in"))
3119 	{
3120 		formatter.setFormattingStyle(STYLE_HORSTMANN);
3121 	}
3122 	else if (isOption(arg, "A10", "style=1tbs") || isOption(arg, "style=otbs"))
3123 	{
3124 		formatter.setFormattingStyle(STYLE_1TBS);
3125 	}
3126 	else if (isOption(arg, "A14", "style=google"))
3127 	{
3128 		formatter.setFormattingStyle(STYLE_GOOGLE);
3129 	}
3130 	else if (isOption(arg, "A16", "style=mozilla"))
3131 	{
3132 		formatter.setFormattingStyle(STYLE_MOZILLA);
3133 	}
3134 	else if (isOption(arg, "A11", "style=pico"))
3135 	{
3136 		formatter.setFormattingStyle(STYLE_PICO);
3137 	}
3138 	else if (isOption(arg, "A12", "style=lisp") || isOption(arg, "style=python"))
3139 	{
3140 		formatter.setFormattingStyle(STYLE_LISP);
3141 	}
3142 	// must check for mode=cs before mode=c !!!
3143 	else if (isOption(arg, "mode=cs"))
3144 	{
3145 		formatter.setSharpStyle();
3146 		formatter.setModeManuallySet(true);
3147 	}
3148 	else if (isOption(arg, "mode=c"))
3149 	{
3150 		formatter.setCStyle();
3151 		formatter.setModeManuallySet(true);
3152 	}
3153 	else if (isOption(arg, "mode=java"))
3154 	{
3155 		formatter.setJavaStyle();
3156 		formatter.setModeManuallySet(true);
3157 	}
3158 	else if (isParamOption(arg, "t", "indent=tab="))
3159 	{
3160 		int spaceNum = 4;
3161 		string spaceNumParam = getParam(arg, "t", "indent=tab=");
3162 		if (spaceNumParam.length() > 0)
3163 			spaceNum = atoi(spaceNumParam.c_str());
3164 		if (spaceNum < 2 || spaceNum > 20)
3165 			isOptionError(arg, errorInfo);
3166 		else
3167 		{
3168 			formatter.setTabIndentation(spaceNum, false);
3169 		}
3170 	}
3171 	else if (isOption(arg, "indent=tab"))
3172 	{
3173 		formatter.setTabIndentation(4);
3174 	}
3175 	else if (isParamOption(arg, "T", "indent=force-tab="))
3176 	{
3177 		int spaceNum = 4;
3178 		string spaceNumParam = getParam(arg, "T", "indent=force-tab=");
3179 		if (spaceNumParam.length() > 0)
3180 			spaceNum = atoi(spaceNumParam.c_str());
3181 		if (spaceNum < 2 || spaceNum > 20)
3182 			isOptionError(arg, errorInfo);
3183 		else
3184 		{
3185 			formatter.setTabIndentation(spaceNum, true);
3186 		}
3187 	}
3188 	else if (isOption(arg, "indent=force-tab"))
3189 	{
3190 		formatter.setTabIndentation(4, true);
3191 	}
3192 	else if (isParamOption(arg, "xT", "indent=force-tab-x="))
3193 	{
3194 		int tabNum = 8;
3195 		string tabNumParam = getParam(arg, "xT", "indent=force-tab-x=");
3196 		if (tabNumParam.length() > 0)
3197 			tabNum = atoi(tabNumParam.c_str());
3198 		if (tabNum < 2 || tabNum > 20)
3199 			isOptionError(arg, errorInfo);
3200 		else
3201 		{
3202 			formatter.setForceTabXIndentation(tabNum);
3203 		}
3204 	}
3205 	else if (isOption(arg, "indent=force-tab-x"))
3206 	{
3207 		formatter.setForceTabXIndentation(8);
3208 	}
3209 	else if (isParamOption(arg, "s", "indent=spaces="))
3210 	{
3211 		int spaceNum = 4;
3212 		string spaceNumParam = getParam(arg, "s", "indent=spaces=");
3213 		if (spaceNumParam.length() > 0)
3214 			spaceNum = atoi(spaceNumParam.c_str());
3215 		if (spaceNum < 2 || spaceNum > 20)
3216 			isOptionError(arg, errorInfo);
3217 		else
3218 		{
3219 			formatter.setSpaceIndentation(spaceNum);
3220 		}
3221 	}
3222 	else if (isOption(arg, "indent=spaces"))
3223 	{
3224 		formatter.setSpaceIndentation(4);
3225 	}
3226 	else if (isParamOption(arg, "xt", "indent-continuation="))
3227 	{
3228 		int contIndent = 1;
3229 		string contIndentParam = getParam(arg, "xt", "indent-continuation=");
3230 		if (contIndentParam.length() > 0)
3231 			contIndent = atoi(contIndentParam.c_str());
3232 		if (contIndent < 0)
3233 			isOptionError(arg, errorInfo);
3234 		else if (contIndent > 4)
3235 			isOptionError(arg, errorInfo);
3236 		else
3237 			formatter.setContinuationIndentation(contIndent);
3238 	}
3239 	else if (isParamOption(arg, "m", "min-conditional-indent="))
3240 	{
3241 		int minIndent = MINCOND_TWO;
3242 		string minIndentParam = getParam(arg, "m", "min-conditional-indent=");
3243 		if (minIndentParam.length() > 0)
3244 			minIndent = atoi(minIndentParam.c_str());
3245 		if (minIndent >= MINCOND_END)
3246 			isOptionError(arg, errorInfo);
3247 		else
3248 			formatter.setMinConditionalIndentOption(minIndent);
3249 	}
3250 	else if (isParamOption(arg, "M", "max-continuation-indent="))
3251 	{
3252 		int maxIndent = 40;
3253 		string maxIndentParam = getParam(arg, "M", "max-continuation-indent=");
3254 		if (maxIndentParam.length() > 0)
3255 			maxIndent = atoi(maxIndentParam.c_str());
3256 		if (maxIndent < 40)
3257 			isOptionError(arg, errorInfo);
3258 		else if (maxIndent > 120)
3259 			isOptionError(arg, errorInfo);
3260 		else
3261 			formatter.setMaxContinuationIndentLength(maxIndent);
3262 	}
3263 	else if (isOption(arg, "N", "indent-namespaces"))
3264 	{
3265 		formatter.setNamespaceIndent(true);
3266 	}
3267 	else if (isOption(arg, "C", "indent-classes"))
3268 	{
3269 		formatter.setClassIndent(true);
3270 	}
3271 	else if (isOption(arg, "xG", "indent-modifiers"))
3272 	{
3273 		formatter.setModifierIndent(true);
3274 	}
3275 	else if (isOption(arg, "S", "indent-switches"))
3276 	{
3277 		formatter.setSwitchIndent(true);
3278 	}
3279 	else if (isOption(arg, "K", "indent-cases"))
3280 	{
3281 		formatter.setCaseIndent(true);
3282 	}
3283 	else if (isOption(arg, "xU", "indent-after-parens"))
3284 	{
3285 		formatter.setAfterParenIndent(true);
3286 	}
3287 	else if (isOption(arg, "L", "indent-labels"))
3288 	{
3289 		formatter.setLabelIndent(true);
3290 	}
3291 	else if (isOption(arg, "xW", "indent-preproc-block"))
3292 	{
3293 		formatter.setPreprocBlockIndent(true);
3294 	}
3295 	else if (isOption(arg, "w", "indent-preproc-define"))
3296 	{
3297 		formatter.setPreprocDefineIndent(true);
3298 	}
3299 	else if (isOption(arg, "xw", "indent-preproc-cond"))
3300 	{
3301 		formatter.setPreprocConditionalIndent(true);
3302 	}
3303 	else if (isOption(arg, "y", "break-closing-braces"))
3304 	{
3305 		formatter.setBreakClosingHeaderBracesMode(true);
3306 	}
3307 	else if (isOption(arg, "O", "keep-one-line-blocks"))
3308 	{
3309 		formatter.setBreakOneLineBlocksMode(false);
3310 	}
3311 	else if (isOption(arg, "o", "keep-one-line-statements"))
3312 	{
3313 		formatter.setBreakOneLineStatementsMode(false);
3314 	}
3315 	else if (isOption(arg, "P", "pad-paren"))
3316 	{
3317 		formatter.setParensOutsidePaddingMode(true);
3318 		formatter.setParensInsidePaddingMode(true);
3319 	}
3320 	else if (isOption(arg, "d", "pad-paren-out"))
3321 	{
3322 		formatter.setParensOutsidePaddingMode(true);
3323 	}
3324 	else if (isOption(arg, "xd", "pad-first-paren-out"))
3325 	{
3326 		formatter.setParensFirstPaddingMode(true);
3327 	}
3328 	else if (isOption(arg, "D", "pad-paren-in"))
3329 	{
3330 		formatter.setParensInsidePaddingMode(true);
3331 	}
3332 	else if (isOption(arg, "H", "pad-header"))
3333 	{
3334 		formatter.setParensHeaderPaddingMode(true);
3335 	}
3336 	else if (isOption(arg, "U", "unpad-paren"))
3337 	{
3338 		formatter.setParensUnPaddingMode(true);
3339 	}
3340 	else if (isOption(arg, "p", "pad-oper"))
3341 	{
3342 		formatter.setOperatorPaddingMode(true);
3343 	}
3344 	else if (isOption(arg, "xg", "pad-comma"))
3345 	{
3346 		formatter.setCommaPaddingMode(true);
3347 	}
3348 	else if (isOption(arg, "xe", "delete-empty-lines"))
3349 	{
3350 		formatter.setDeleteEmptyLinesMode(true);
3351 	}
3352 	else if (isOption(arg, "E", "fill-empty-lines"))
3353 	{
3354 		formatter.setEmptyLineFill(true);
3355 	}
3356 	else if (isOption(arg, "c", "convert-tabs"))
3357 	{
3358 		formatter.setTabSpaceConversionMode(true);
3359 	}
3360 	else if (isOption(arg, "xy", "close-templates"))
3361 	{
3362 		formatter.setCloseTemplatesMode(true);
3363 	}
3364 	else if (isOption(arg, "F", "break-blocks=all"))
3365 	{
3366 		formatter.setBreakBlocksMode(true);
3367 		formatter.setBreakClosingHeaderBlocksMode(true);
3368 	}
3369 	else if (isOption(arg, "f", "break-blocks"))
3370 	{
3371 		formatter.setBreakBlocksMode(true);
3372 	}
3373 	else if (isOption(arg, "e", "break-elseifs"))
3374 	{
3375 		formatter.setBreakElseIfsMode(true);
3376 	}
3377 	else if (isOption(arg, "xb", "break-one-line-headers"))
3378 	{
3379 		formatter.setBreakOneLineHeadersMode(true);
3380 	}
3381 	else if (isOption(arg, "j", "add-braces"))
3382 	{
3383 		formatter.setAddBracesMode(true);
3384 	}
3385 	else if (isOption(arg, "J", "add-one-line-braces"))
3386 	{
3387 		formatter.setAddOneLineBracesMode(true);
3388 	}
3389 	else if (isOption(arg, "xj", "remove-braces"))
3390 	{
3391 		formatter.setRemoveBracesMode(true);
3392 	}
3393 	else if (isOption(arg, "Y", "indent-col1-comments"))
3394 	{
3395 		formatter.setIndentCol1CommentsMode(true);
3396 	}
3397 	else if (isOption(arg, "align-pointer=type"))
3398 	{
3399 		formatter.setPointerAlignment(PTR_ALIGN_TYPE);
3400 	}
3401 	else if (isOption(arg, "align-pointer=middle"))
3402 	{
3403 		formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
3404 	}
3405 	else if (isOption(arg, "align-pointer=name"))
3406 	{
3407 		formatter.setPointerAlignment(PTR_ALIGN_NAME);
3408 	}
3409 	else if (isParamOption(arg, "k"))
3410 	{
3411 		int align = 0;
3412 		string styleParam = getParam(arg, "k");
3413 		if (styleParam.length() > 0)
3414 			align = atoi(styleParam.c_str());
3415 		if (align < 1 || align > 3)
3416 			isOptionError(arg, errorInfo);
3417 		else if (align == 1)
3418 			formatter.setPointerAlignment(PTR_ALIGN_TYPE);
3419 		else if (align == 2)
3420 			formatter.setPointerAlignment(PTR_ALIGN_MIDDLE);
3421 		else if (align == 3)
3422 			formatter.setPointerAlignment(PTR_ALIGN_NAME);
3423 	}
3424 	else if (isOption(arg, "align-reference=none"))
3425 	{
3426 		formatter.setReferenceAlignment(REF_ALIGN_NONE);
3427 	}
3428 	else if (isOption(arg, "align-reference=type"))
3429 	{
3430 		formatter.setReferenceAlignment(REF_ALIGN_TYPE);
3431 	}
3432 	else if (isOption(arg, "align-reference=middle"))
3433 	{
3434 		formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
3435 	}
3436 	else if (isOption(arg, "align-reference=name"))
3437 	{
3438 		formatter.setReferenceAlignment(REF_ALIGN_NAME);
3439 	}
3440 	else if (isParamOption(arg, "W"))
3441 	{
3442 		int align = 0;
3443 		string styleParam = getParam(arg, "W");
3444 		if (styleParam.length() > 0)
3445 			align = atoi(styleParam.c_str());
3446 		if (align < 0 || align > 3)
3447 			isOptionError(arg, errorInfo);
3448 		else if (align == 0)
3449 			formatter.setReferenceAlignment(REF_ALIGN_NONE);
3450 		else if (align == 1)
3451 			formatter.setReferenceAlignment(REF_ALIGN_TYPE);
3452 		else if (align == 2)
3453 			formatter.setReferenceAlignment(REF_ALIGN_MIDDLE);
3454 		else if (align == 3)
3455 			formatter.setReferenceAlignment(REF_ALIGN_NAME);
3456 	}
3457 	else if (isParamOption(arg, "max-code-length="))
3458 	{
3459 		int maxLength = 50;
3460 		string maxLengthParam = getParam(arg, "max-code-length=");
3461 		if (maxLengthParam.length() > 0)
3462 			maxLength = atoi(maxLengthParam.c_str());
3463 		if (maxLength < 50)
3464 			isOptionError(arg, errorInfo);
3465 		else if (maxLength > 200)
3466 			isOptionError(arg, errorInfo);
3467 		else
3468 			formatter.setMaxCodeLength(maxLength);
3469 	}
3470 	else if (isParamOption(arg, "xC"))
3471 	{
3472 		int maxLength = 50;
3473 		string maxLengthParam = getParam(arg, "xC");
3474 		if (maxLengthParam.length() > 0)
3475 			maxLength = atoi(maxLengthParam.c_str());
3476 		if (maxLength > 200)
3477 			isOptionError(arg, errorInfo);
3478 		else
3479 			formatter.setMaxCodeLength(maxLength);
3480 	}
3481 	else if (isOption(arg, "xL", "break-after-logical"))
3482 	{
3483 		formatter.setBreakAfterMode(true);
3484 	}
3485 	else if (isOption(arg, "xc", "attach-classes"))
3486 	{
3487 		formatter.setAttachClass(true);
3488 	}
3489 	else if (isOption(arg, "xV", "attach-closing-while"))
3490 	{
3491 		formatter.setAttachClosingWhile(true);
3492 	}
3493 	else if (isOption(arg, "xk", "attach-extern-c"))
3494 	{
3495 		formatter.setAttachExternC(true);
3496 	}
3497 	else if (isOption(arg, "xn", "attach-namespaces"))
3498 	{
3499 		formatter.setAttachNamespace(true);
3500 	}
3501 	else if (isOption(arg, "xl", "attach-inlines"))
3502 	{
3503 		formatter.setAttachInline(true);
3504 	}
3505 	else if (isOption(arg, "xp", "remove-comment-prefix"))
3506 	{
3507 		formatter.setStripCommentPrefix(true);
3508 	}
3509 	else if (isOption(arg, "xB", "break-return-type"))
3510 	{
3511 		formatter.setBreakReturnType(true);
3512 	}
3513 	else if (isOption(arg, "xD", "break-return-type-decl"))
3514 	{
3515 		formatter.setBreakReturnTypeDecl(true);
3516 	}
3517 	else if (isOption(arg, "xf", "attach-return-type"))
3518 	{
3519 		formatter.setAttachReturnType(true);
3520 	}
3521 	else if (isOption(arg, "xh", "attach-return-type-decl"))
3522 	{
3523 		formatter.setAttachReturnTypeDecl(true);
3524 	}
3525 	// Objective-C options
3526 	else if (isOption(arg, "xQ", "pad-method-prefix"))
3527 	{
3528 		formatter.setMethodPrefixPaddingMode(true);
3529 	}
3530 	else if (isOption(arg, "xR", "unpad-method-prefix"))
3531 	{
3532 		formatter.setMethodPrefixUnPaddingMode(true);
3533 	}
3534 	else if (isOption(arg, "xq", "pad-return-type"))
3535 	{
3536 		formatter.setReturnTypePaddingMode(true);
3537 	}
3538 	else if (isOption(arg, "xr", "unpad-return-type"))
3539 	{
3540 		formatter.setReturnTypeUnPaddingMode(true);
3541 	}
3542 	else if (isOption(arg, "xS", "pad-param-type"))
3543 	{
3544 		formatter.setParamTypePaddingMode(true);
3545 	}
3546 	else if (isOption(arg, "xs", "unpad-param-type"))
3547 	{
3548 		formatter.setParamTypeUnPaddingMode(true);
3549 	}
3550 	else if (isOption(arg, "xM", "align-method-colon"))
3551 	{
3552 		formatter.setAlignMethodColon(true);
3553 	}
3554 	else if (isOption(arg, "xP0", "pad-method-colon=none"))
3555 	{
3556 		formatter.setObjCColonPaddingMode(COLON_PAD_NONE);
3557 	}
3558 	else if (isOption(arg, "xP1", "pad-method-colon=all"))
3559 	{
3560 		formatter.setObjCColonPaddingMode(COLON_PAD_ALL);
3561 	}
3562 	else if (isOption(arg, "xP2", "pad-method-colon=after"))
3563 	{
3564 		formatter.setObjCColonPaddingMode(COLON_PAD_AFTER);
3565 	}
3566 	else if (isOption(arg, "xP3", "pad-method-colon=before"))
3567 	{
3568 		formatter.setObjCColonPaddingMode(COLON_PAD_BEFORE);
3569 	}
3570 	// NOTE: depreciated options - remove when appropriate
3571 	// depreciated options ////////////////////////////////////////////////////////////////////////
3572 	else if (isOption(arg, "indent-preprocessor"))		// depreciated release 2.04
3573 	{
3574 		formatter.setPreprocDefineIndent(true);
3575 	}
3576 	else if (isOption(arg, "style=ansi"))					// depreciated release 2.05
3577 	{
3578 		formatter.setFormattingStyle(STYLE_ALLMAN);
3579 	}
3580 	// depreciated in release 3.0 /////////////////////////////////////////////////////////////////
3581 	else if (isOption(arg, "break-closing-brackets"))		// depreciated release 3.0
3582 	{
3583 		formatter.setBreakClosingHeaderBracketsMode(true);
3584 	}
3585 	else if (isOption(arg, "add-brackets"))				// depreciated release 3.0
3586 	{
3587 		formatter.setAddBracketsMode(true);
3588 	}
3589 	else if (isOption(arg, "add-one-line-brackets"))		// depreciated release 3.0
3590 	{
3591 		formatter.setAddOneLineBracketsMode(true);
3592 	}
3593 	else if (isOption(arg, "remove-brackets"))			// depreciated release 3.0
3594 	{
3595 		formatter.setRemoveBracketsMode(true);
3596 	}
3597 	else if (isParamOption(arg, "max-instatement-indent="))	// depreciated release 3.0
3598 	{
3599 		int maxIndent = 40;
3600 		string maxIndentParam = getParam(arg, "max-instatement-indent=");
3601 		if (maxIndentParam.length() > 0)
3602 			maxIndent = atoi(maxIndentParam.c_str());
3603 		if (maxIndent < 40)
3604 			isOptionError(arg, errorInfo);
3605 		else if (maxIndent > 120)
3606 			isOptionError(arg, errorInfo);
3607 		else
3608 			formatter.setMaxInStatementIndentLength(maxIndent);
3609 	}
3610 	// end depreciated options ////////////////////////////////////////////////////////////////////
3611 #ifdef ASTYLE_LIB
3612 	// End of options used by GUI /////////////////////////////////////////////////////////////////
3613 	else
3614 		isOptionError(arg, errorInfo);
3615 #else
3616 	// Options used by only console ///////////////////////////////////////////////////////////////
3617 	else if (isOption(arg, "n", "suffix=none"))
3618 	{
3619 		console.setNoBackup(true);
3620 	}
3621 	else if (isParamOption(arg, "suffix="))
3622 	{
3623 		string suffixParam = getParam(arg, "suffix=");
3624 		if (suffixParam.length() > 0)
3625 		{
3626 			console.setOrigSuffix(suffixParam);
3627 		}
3628 	}
3629 	else if (isParamOption(arg, "exclude="))
3630 	{
3631 		string suffixParam = getParam(arg, "exclude=");
3632 		if (suffixParam.length() > 0)
3633 			console.updateExcludeVector(suffixParam);
3634 	}
3635 	else if (isOption(arg, "r", "R") || isOption(arg, "recursive"))
3636 	{
3637 		console.setIsRecursive(true);
3638 	}
3639 	else if (isOption(arg, "dry-run"))
3640 	{
3641 		console.setIsDryRun(true);
3642 	}
3643 	else if (isOption(arg, "Z", "preserve-date"))
3644 	{
3645 		console.setPreserveDate(true);
3646 	}
3647 	else if (isOption(arg, "v", "verbose"))
3648 	{
3649 		console.setIsVerbose(true);
3650 	}
3651 	else if (isOption(arg, "Q", "formatted"))
3652 	{
3653 		console.setIsFormattedOnly(true);
3654 	}
3655 	else if (isOption(arg, "q", "quiet"))
3656 	{
3657 		console.setIsQuiet(true);
3658 	}
3659 	else if (isOption(arg, "i", "ignore-exclude-errors"))
3660 	{
3661 		console.setIgnoreExcludeErrors(true);
3662 	}
3663 	else if (isOption(arg, "xi", "ignore-exclude-errors-x"))
3664 	{
3665 		console.setIgnoreExcludeErrorsAndDisplay(true);
3666 	}
3667 	else if (isOption(arg, "X", "errors-to-stdout"))
3668 	{
3669 		console.setErrorStream(&cout);
3670 	}
3671 	else if (isOption(arg, "lineend=windows"))
3672 	{
3673 		formatter.setLineEndFormat(LINEEND_WINDOWS);
3674 	}
3675 	else if (isOption(arg, "lineend=linux"))
3676 	{
3677 		formatter.setLineEndFormat(LINEEND_LINUX);
3678 	}
3679 	else if (isOption(arg, "lineend=macold"))
3680 	{
3681 		formatter.setLineEndFormat(LINEEND_MACOLD);
3682 	}
3683 	else if (isParamOption(arg, "z"))
3684 	{
3685 		int lineendType = 0;
3686 		string lineendParam = getParam(arg, "z");
3687 		if (lineendParam.length() > 0)
3688 			lineendType = atoi(lineendParam.c_str());
3689 		if (lineendType < 1 || lineendType > 3)
3690 			isOptionError(arg, errorInfo);
3691 		else if (lineendType == 1)
3692 			formatter.setLineEndFormat(LINEEND_WINDOWS);
3693 		else if (lineendType == 2)
3694 			formatter.setLineEndFormat(LINEEND_LINUX);
3695 		else if (lineendType == 3)
3696 			formatter.setLineEndFormat(LINEEND_MACOLD);
3697 	}
3698 	else
3699 		isOptionError(arg, errorInfo);
3700 #endif
3701 }	// End of parseOption function
3702 
3703 // Parse options from the option file.
importOptions(stringstream & in,vector<string> & optionsVector)3704 void ASOptions::importOptions(stringstream& in, vector<string>& optionsVector)
3705 {
3706 	char ch;
3707 	bool isInQuote = false;
3708 	char quoteChar = ' ';
3709 	string currentToken;
3710 
3711 	while (in)
3712 	{
3713 		currentToken = "";
3714 		do
3715 		{
3716 			in.get(ch);
3717 			if (in.eof())
3718 				break;
3719 			// treat '#' as line comments
3720 			if (ch == '#')
3721 				while (in)
3722 				{
3723 					in.get(ch);
3724 					if (ch == '\n' || ch == '\r')
3725 						break;
3726 				}
3727 
3728 			// break options on new-lines, tabs, commas, or spaces
3729 			// remove quotes from output
3730 			if (in.eof() || ch == '\n' || ch == '\r' || ch == '\t' || ch == ',')
3731 				break;
3732 			if (ch == ' ' && !isInQuote)
3733 				break;
3734 			if (ch == quoteChar && isInQuote)
3735 				break;
3736 			if (ch == '"' || ch == '\'')
3737 			{
3738 				isInQuote = true;
3739 				quoteChar = ch;
3740 				continue;
3741 			}
3742 			currentToken.append(1, ch);
3743 		}
3744 		while (in);
3745 
3746 		if (currentToken.length() != 0)
3747 			optionsVector.emplace_back(currentToken);
3748 		isInQuote = false;
3749 	}
3750 }
3751 
getOptionErrors() const3752 string ASOptions::getOptionErrors() const
3753 {
3754 	return optionErrors.str();
3755 }
3756 
getParam(const string & arg,const char * op)3757 string ASOptions::getParam(const string& arg, const char* op)
3758 {
3759 	return arg.substr(strlen(op));
3760 }
3761 
getParam(const string & arg,const char * op1,const char * op2)3762 string ASOptions::getParam(const string& arg, const char* op1, const char* op2)
3763 {
3764 	return isParamOption(arg, op1) ? getParam(arg, op1) : getParam(arg, op2);
3765 }
3766 
isOption(const string & arg,const char * op)3767 bool ASOptions::isOption(const string& arg, const char* op)
3768 {
3769 	return arg.compare(op) == 0;
3770 }
3771 
isOption(const string & arg,const char * op1,const char * op2)3772 bool ASOptions::isOption(const string& arg, const char* op1, const char* op2)
3773 {
3774 	return (isOption(arg, op1) || isOption(arg, op2));
3775 }
3776 
isOptionError(const string & arg,const string & errorInfo)3777 void ASOptions::isOptionError(const string& arg, const string& errorInfo)
3778 {
3779 	if (optionErrors.str().length() == 0)
3780 		optionErrors << errorInfo << endl;   // need main error message
3781 	optionErrors << "\t" << arg << endl;
3782 }
3783 
isParamOption(const string & arg,const char * option)3784 bool ASOptions::isParamOption(const string& arg, const char* option)
3785 {
3786 	bool retVal = arg.compare(0, strlen(option), option) == 0;
3787 	// if comparing for short option, 2nd char of arg must be numeric
3788 	if (retVal && strlen(option) == 1 && arg.length() > 1)
3789 		if (!isdigit((unsigned char) arg[1]))
3790 			retVal = false;
3791 	return retVal;
3792 }
3793 
isParamOption(const string & arg,const char * option1,const char * option2)3794 bool ASOptions::isParamOption(const string& arg, const char* option1, const char* option2)
3795 {
3796 	return isParamOption(arg, option1) || isParamOption(arg, option2);
3797 }
3798 
3799 //----------------------------------------------------------------------------
3800 // ASEncoding class
3801 //----------------------------------------------------------------------------
3802 
3803 // Return true if an int is big endian.
getBigEndian() const3804 bool ASEncoding::getBigEndian() const
3805 {
3806 	char16_t word = 0x0001;
3807 	char* byte = (char*) &word;
3808 	return (byte[0] ? false : true);
3809 }
3810 
3811 // Swap the two low order bytes of a 16 bit integer value.
swap16bit(int value) const3812 int ASEncoding::swap16bit(int value) const
3813 {
3814 	return (((value & 0xff) << 8) | ((value & 0xff00) >> 8));
3815 }
3816 
3817 // Return the length of a utf-16 C string.
3818 // The length is in number of char16_t.
utf16len(const utf16 * utf16In) const3819 size_t ASEncoding::utf16len(const utf16* utf16In) const
3820 {
3821 	size_t length = 0;
3822 	while (*utf16In++ != '\0')
3823 		length++;
3824 	return length;
3825 }
3826 
3827 // Adapted from SciTE UniConversion.cxx.
3828 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
3829 // Modified for Artistic Style by Jim Pattee.
3830 // Compute the length of an output utf-8 file given a utf-16 file.
3831 // Input inLen is the size in BYTES (not wchar_t).
utf8LengthFromUtf16(const char * utf16In,size_t inLen,bool isBigEndian) const3832 size_t ASEncoding::utf8LengthFromUtf16(const char* utf16In, size_t inLen, bool isBigEndian) const
3833 {
3834 	size_t len = 0;
3835 	size_t wcharLen = (inLen / 2) + (inLen % 2);
3836 	const char16_t* uptr = reinterpret_cast<const char16_t*>(utf16In);
3837 	for (size_t i = 0; i < wcharLen;)
3838 	{
3839 		size_t uch = isBigEndian ? swap16bit(uptr[i]) : uptr[i];
3840 		if (uch < 0x80)
3841 			len++;
3842 		else if (uch < 0x800)
3843 			len += 2;
3844 		else if ((uch >= SURROGATE_LEAD_FIRST) && (uch <= SURROGATE_LEAD_LAST))
3845 		{
3846 			len += 4;
3847 			i++;
3848 		}
3849 		else
3850 			len += 3;
3851 		i++;
3852 	}
3853 	return len;
3854 }
3855 
3856 // Adapted from SciTE Utf8_16.cxx.
3857 // Copyright (C) 2002 Scott Kirkwood.
3858 // Modified for Artistic Style by Jim Pattee.
3859 // Convert a utf-8 file to utf-16.
utf8ToUtf16(char * utf8In,size_t inLen,bool isBigEndian,char * utf16Out) const3860 size_t ASEncoding::utf8ToUtf16(char* utf8In, size_t inLen, bool isBigEndian, char* utf16Out) const
3861 {
3862 	int nCur = 0;
3863 	ubyte* pRead = reinterpret_cast<ubyte*>(utf8In);
3864 	utf16* pCur = reinterpret_cast<utf16*>(utf16Out);
3865 	const ubyte* pEnd = pRead + inLen;
3866 	const utf16* pCurStart = pCur;
3867 	eState state = eStart;
3868 
3869 	// the BOM will automatically be converted to utf-16
3870 	while (pRead < pEnd)
3871 	{
3872 		switch (state)
3873 		{
3874 			case eStart:
3875 				if ((0xF0 & *pRead) == 0xF0)
3876 				{
3877 					nCur = (0x7 & *pRead) << 18;
3878 					state = eSecondOf4Bytes;
3879 				}
3880 				else if ((0xE0 & *pRead) == 0xE0)
3881 				{
3882 					nCur = (~0xE0 & *pRead) << 12;
3883 					state = ePenultimate;
3884 				}
3885 				else if ((0xC0 & *pRead) == 0xC0)
3886 				{
3887 					nCur = (~0xC0 & *pRead) << 6;
3888 					state = eFinal;
3889 				}
3890 				else
3891 				{
3892 					nCur = *pRead;
3893 					state = eStart;
3894 				}
3895 				break;
3896 			case eSecondOf4Bytes:
3897 				nCur |= (0x3F & *pRead) << 12;
3898 				state = ePenultimate;
3899 				break;
3900 			case ePenultimate:
3901 				nCur |= (0x3F & *pRead) << 6;
3902 				state = eFinal;
3903 				break;
3904 			case eFinal:
3905 				nCur |= (0x3F & *pRead);
3906 				state = eStart;
3907 				break;
3908 				// no default case is needed
3909 		}
3910 		++pRead;
3911 
3912 		if (state == eStart)
3913 		{
3914 			int codePoint = nCur;
3915 			if (codePoint >= SURROGATE_FIRST_VALUE)
3916 			{
3917 				codePoint -= SURROGATE_FIRST_VALUE;
3918 				int lead = (codePoint >> 10) + SURROGATE_LEAD_FIRST;
3919 				*pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(lead) : lead);
3920 				int trail = (codePoint & 0x3ff) + SURROGATE_TRAIL_FIRST;
3921 				*pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(trail) : trail);
3922 			}
3923 			else
3924 				*pCur++ = static_cast<utf16>(isBigEndian ? swap16bit(codePoint) : codePoint);
3925 		}
3926 	}
3927 	// return value is the output length in BYTES (not wchar_t)
3928 	return (pCur - pCurStart) * 2;
3929 }
3930 
3931 // Adapted from SciTE UniConversion.cxx.
3932 // Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
3933 // Modified for Artistic Style by Jim Pattee.
3934 // Compute the length of an output utf-16 file given a utf-8 file.
3935 // Return value is the size in BYTES (not wchar_t).
utf16LengthFromUtf8(const char * utf8In,size_t len) const3936 size_t ASEncoding::utf16LengthFromUtf8(const char* utf8In, size_t len) const
3937 {
3938 	size_t ulen = 0;
3939 	size_t charLen;
3940 	for (size_t i = 0; i < len;)
3941 	{
3942 		unsigned char ch = static_cast<unsigned char>(utf8In[i]);
3943 		if (ch < 0x80)
3944 			charLen = 1;
3945 		else if (ch < 0x80 + 0x40 + 0x20)
3946 			charLen = 2;
3947 		else if (ch < 0x80 + 0x40 + 0x20 + 0x10)
3948 			charLen = 3;
3949 		else
3950 		{
3951 			charLen = 4;
3952 			ulen++;
3953 		}
3954 		i += charLen;
3955 		ulen++;
3956 	}
3957 	// return value is the length in bytes (not wchar_t)
3958 	return ulen * 2;
3959 }
3960 
3961 // Adapted from SciTE Utf8_16.cxx.
3962 // Copyright (C) 2002 Scott Kirkwood.
3963 // Modified for Artistic Style by Jim Pattee.
3964 // Convert a utf-16 file to utf-8.
utf16ToUtf8(char * utf16In,size_t inLen,bool isBigEndian,bool firstBlock,char * utf8Out) const3965 size_t ASEncoding::utf16ToUtf8(char* utf16In, size_t inLen, bool isBigEndian,
3966                                bool firstBlock, char* utf8Out) const
3967 {
3968 	int nCur16 = 0;
3969 	int nCur = 0;
3970 	ubyte* pRead = reinterpret_cast<ubyte*>(utf16In);
3971 	ubyte* pCur = reinterpret_cast<ubyte*>(utf8Out);
3972 	const ubyte* pEnd = pRead + inLen;
3973 	const ubyte* pCurStart = pCur;
3974 	static eState state = eStart;	// state is retained for subsequent blocks
3975 	if (firstBlock)
3976 		state = eStart;
3977 
3978 	// the BOM will automatically be converted to utf-8
3979 	while (pRead < pEnd)
3980 	{
3981 		switch (state)
3982 		{
3983 			case eStart:
3984 				if (pRead >= pEnd)
3985 				{
3986 					++pRead;
3987 					break;
3988 				}
3989 				if (isBigEndian)
3990 				{
3991 					nCur16 = static_cast<utf16>(*pRead++ << 8);
3992 					nCur16 |= static_cast<utf16>(*pRead);
3993 				}
3994 				else
3995 				{
3996 					nCur16 = *pRead++;
3997 					nCur16 |= static_cast<utf16>(*pRead << 8);
3998 				}
3999 				if (nCur16 >= SURROGATE_LEAD_FIRST && nCur16 <= SURROGATE_LEAD_LAST)
4000 				{
4001 					++pRead;
4002 					int trail;
4003 					if (isBigEndian)
4004 					{
4005 						trail = static_cast<utf16>(*pRead++ << 8);
4006 						trail |= static_cast<utf16>(*pRead);
4007 					}
4008 					else
4009 					{
4010 						trail = *pRead++;
4011 						trail |= static_cast<utf16>(*pRead << 8);
4012 					}
4013 					nCur16 = (((nCur16 & 0x3ff) << 10) | (trail & 0x3ff)) + SURROGATE_FIRST_VALUE;
4014 				}
4015 				++pRead;
4016 
4017 				if (nCur16 < 0x80)
4018 				{
4019 					nCur = static_cast<ubyte>(nCur16 & 0xFF);
4020 					state = eStart;
4021 				}
4022 				else if (nCur16 < 0x800)
4023 				{
4024 					nCur = static_cast<ubyte>(0xC0 | (nCur16 >> 6));
4025 					state = eFinal;
4026 				}
4027 				else if (nCur16 < SURROGATE_FIRST_VALUE)
4028 				{
4029 					nCur = static_cast<ubyte>(0xE0 | (nCur16 >> 12));
4030 					state = ePenultimate;
4031 				}
4032 				else
4033 				{
4034 					nCur = static_cast<ubyte>(0xF0 | (nCur16 >> 18));
4035 					state = eSecondOf4Bytes;
4036 				}
4037 				break;
4038 			case eSecondOf4Bytes:
4039 				nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 12) & 0x3F));
4040 				state = ePenultimate;
4041 				break;
4042 			case ePenultimate:
4043 				nCur = static_cast<ubyte>(0x80 | ((nCur16 >> 6) & 0x3F));
4044 				state = eFinal;
4045 				break;
4046 			case eFinal:
4047 				nCur = static_cast<ubyte>(0x80 | (nCur16 & 0x3F));
4048 				state = eStart;
4049 				break;
4050 				// no default case is needed
4051 		}
4052 		*pCur++ = static_cast<ubyte>(nCur);
4053 	}
4054 	return pCur - pCurStart;
4055 }
4056 
4057 //----------------------------------------------------------------------------
4058 
4059 }   // namespace astyle
4060 
4061 //----------------------------------------------------------------------------
4062 
4063 using namespace astyle;
4064 
4065 //----------------------------------------------------------------------------
4066 // ASTYLE_JNI functions for Java library builds
4067 //----------------------------------------------------------------------------
4068 
4069 #ifdef ASTYLE_JNI
4070 
4071 // called by a java program to get the version number
4072 // the function name is constructed from method names in the calling java program
4073 extern "C"  EXPORT
Java_AStyleInterface_AStyleGetVersion(JNIEnv * env,jclass)4074 jstring STDCALL Java_AStyleInterface_AStyleGetVersion(JNIEnv* env, jclass)
4075 {
4076 	return env->NewStringUTF(g_version);
4077 }
4078 
4079 // called by a java program to format the source code
4080 // the function name is constructed from method names in the calling java program
4081 extern "C"  EXPORT
Java_AStyleInterface_AStyleMain(JNIEnv * env,jobject obj,jstring textInJava,jstring optionsJava)4082 jstring STDCALL Java_AStyleInterface_AStyleMain(JNIEnv* env,
4083                                                 jobject obj,
4084                                                 jstring textInJava,
4085                                                 jstring optionsJava)
4086 {
4087 	g_env = env;                                // make object available globally
4088 	g_obj = obj;                                // make object available globally
4089 
4090 	jstring textErr = env->NewStringUTF("");    // zero length text returned if an error occurs
4091 
4092 	// get the method ID
4093 	jclass cls = env->GetObjectClass(obj);
4094 	g_mid = env->GetMethodID(cls, "ErrorHandler", "(ILjava/lang/String;)V");
4095 	if (g_mid == nullptr)
4096 	{
4097 		cout << "Cannot find java method ErrorHandler" << endl;
4098 		return textErr;
4099 	}
4100 
4101 	// convert jstring to char*
4102 	const char* textIn = env->GetStringUTFChars(textInJava, nullptr);
4103 	const char* options = env->GetStringUTFChars(optionsJava, nullptr);
4104 
4105 	// call the C++ formatting function
4106 	char* textOut = AStyleMain(textIn, options, javaErrorHandler, javaMemoryAlloc);
4107 	// if an error message occurred it was displayed by errorHandler
4108 	if (textOut == nullptr)
4109 		return textErr;
4110 
4111 	// release memory
4112 	jstring textOutJava = env->NewStringUTF(textOut);
4113 	delete[] textOut;
4114 	env->ReleaseStringUTFChars(textInJava, textIn);
4115 	env->ReleaseStringUTFChars(optionsJava, options);
4116 
4117 	return textOutJava;
4118 }
4119 
4120 // Call the Java error handler
javaErrorHandler(int errorNumber,const char * errorMessage)4121 void STDCALL javaErrorHandler(int errorNumber, const char* errorMessage)
4122 {
4123 	jstring errorMessageJava = g_env->NewStringUTF(errorMessage);
4124 	g_env->CallVoidMethod(g_obj, g_mid, errorNumber, errorMessageJava);
4125 }
4126 
4127 // Allocate memory for the formatted text
javaMemoryAlloc(unsigned long memoryNeeded)4128 char* STDCALL javaMemoryAlloc(unsigned long memoryNeeded)
4129 {
4130 	// error condition is checked after return from AStyleMain
4131 	char* buffer = new (nothrow) char[memoryNeeded];
4132 	return buffer;
4133 }
4134 
4135 #endif	// ASTYLE_JNI
4136 
4137 //----------------------------------------------------------------------------
4138 // ASTYLE_LIB functions for library builds
4139 //----------------------------------------------------------------------------
4140 
4141 #ifdef ASTYLE_LIB
4142 
4143 //----------------------------------------------------------------------------
4144 // ASTYLE_LIB entry point for AStyleMainUtf16 library builds
4145 //----------------------------------------------------------------------------
4146 /*
4147 * IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
4148 *           /EXPORT:AStyleMain=_AStyleMain@16
4149 *           /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
4150 *           /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
4151 * No /EXPORT is required for x64
4152 */
AStyleMainUtf16(const char16_t * pSourceIn,const char16_t * pOptions,fpError fpErrorHandler,fpAlloc fpMemoryAlloc)4153 extern "C" EXPORT char16_t* STDCALL AStyleMainUtf16(const char16_t* pSourceIn,	// the source to be formatted
4154                                                     const char16_t* pOptions,	// AStyle options
4155                                                     fpError fpErrorHandler,		// error handler function
4156                                                     fpAlloc fpMemoryAlloc)		// memory allocation function
4157 {
4158 	if (fpErrorHandler == nullptr)         // cannot display a message if no error handler
4159 		return nullptr;
4160 
4161 	if (pSourceIn == nullptr)
4162 	{
4163 		fpErrorHandler(101, "No pointer to source input.");
4164 		return nullptr;
4165 	}
4166 	if (pOptions == nullptr)
4167 	{
4168 		fpErrorHandler(102, "No pointer to AStyle options.");
4169 		return nullptr;
4170 	}
4171 	if (fpMemoryAlloc == nullptr)
4172 	{
4173 		fpErrorHandler(103, "No pointer to memory allocation function.");
4174 		return nullptr;
4175 	}
4176 #ifndef _WIN32
4177 	// check size of char16_t on Linux
4178 	int sizeCheck = 2;
4179 	if (sizeof(char16_t) != sizeCheck)
4180 	{
4181 		fpErrorHandler(104, "char16_t is not the correct size.");
4182 		return nullptr;
4183 	}
4184 #endif
4185 
4186 	ASLibrary library;
4187 	char16_t* utf16Out = library.formatUtf16(pSourceIn, pOptions, fpErrorHandler, fpMemoryAlloc);
4188 	return utf16Out;
4189 }
4190 
4191 //----------------------------------------------------------------------------
4192 // ASTYLE_LIB entry point for library builds
4193 //----------------------------------------------------------------------------
4194 /*
4195  * IMPORTANT Visual C DLL linker for WIN32 must have the additional options:
4196  *           /EXPORT:AStyleMain=_AStyleMain@16
4197  *           /EXPORT:AStyleMainUtf16=_AStyleMainUtf16@16
4198  *           /EXPORT:AStyleGetVersion=_AStyleGetVersion@0
4199  * No /EXPORT is required for x64
4200  */
AStyleMain(const char * pSourceIn,const char * pOptions,fpError fpErrorHandler,fpAlloc fpMemoryAlloc)4201 extern "C" EXPORT char* STDCALL AStyleMain(const char* pSourceIn,		// the source to be formatted
4202                                            const char* pOptions,		// AStyle options
4203                                            fpError fpErrorHandler,		// error handler function
4204                                            fpAlloc fpMemoryAlloc)		// memory allocation function
4205 {
4206 	if (fpErrorHandler == nullptr)         // cannot display a message if no error handler
4207 		return nullptr;
4208 
4209 	if (pSourceIn == nullptr)
4210 	{
4211 		fpErrorHandler(101, "No pointer to source input.");
4212 		return nullptr;
4213 	}
4214 	if (pOptions == nullptr)
4215 	{
4216 		fpErrorHandler(102, "No pointer to AStyle options.");
4217 		return nullptr;
4218 	}
4219 	if (fpMemoryAlloc == nullptr)
4220 	{
4221 		fpErrorHandler(103, "No pointer to memory allocation function.");
4222 		return nullptr;
4223 	}
4224 
4225 	ASFormatter formatter;
4226 	ASOptions options(formatter);
4227 
4228 	vector<string> optionsVector;
4229 	stringstream opt(pOptions);
4230 
4231 	options.importOptions(opt, optionsVector);
4232 
4233 	bool ok = options.parseOptions(optionsVector, "Invalid Artistic Style options:");
4234 	if (!ok)
4235 		fpErrorHandler(130, options.getOptionErrors().c_str());
4236 
4237 	stringstream in(pSourceIn);
4238 	ASStreamIterator<stringstream> streamIterator(&in);
4239 	ostringstream out;
4240 	formatter.init(&streamIterator);
4241 
4242 	while (formatter.hasMoreLines())
4243 	{
4244 		out << formatter.nextLine();
4245 		if (formatter.hasMoreLines())
4246 			out << streamIterator.getOutputEOL();
4247 		else
4248 		{
4249 			// this can happen if the file if missing a closing brace and break-blocks is requested
4250 			if (formatter.getIsLineReady())
4251 			{
4252 				out << streamIterator.getOutputEOL();
4253 				out << formatter.nextLine();
4254 			}
4255 		}
4256 	}
4257 
4258 	size_t textSizeOut = out.str().length();
4259 	char* pTextOut = fpMemoryAlloc((long) textSizeOut + 1);     // call memory allocation function
4260 	if (pTextOut == nullptr)
4261 	{
4262 		fpErrorHandler(120, "Allocation failure on output.");
4263 		return nullptr;
4264 	}
4265 
4266 	strcpy(pTextOut, out.str().c_str());
4267 #ifndef NDEBUG
4268 	// The checksum is an assert in the console build and ASFormatter.
4269 	// This error returns the incorrectly formatted file to the editor.
4270 	// This is done to allow the file to be saved for debugging purposes.
4271 	if (formatter.getChecksumDiff() != 0)
4272 		fpErrorHandler(220,
4273 		               "Checksum error.\n"
4274 		               "The incorrectly formatted file will be returned for debugging.");
4275 #endif
4276 	return pTextOut;
4277 }
4278 
AStyleGetVersion(void)4279 extern "C" EXPORT const char* STDCALL AStyleGetVersion(void)
4280 {
4281 	return g_version;
4282 }
4283 
4284 // ASTYLECON_LIB is defined to exclude "main" from the test programs
4285 #elif !defined(ASTYLECON_LIB)
4286 
4287 //----------------------------------------------------------------------------
4288 // main function for ASConsole build
4289 //----------------------------------------------------------------------------
4290 
main(int argc,char ** argv)4291 int main(int argc, char** argv)
4292 {
4293 	// create objects
4294 	ASFormatter formatter;
4295 	unique_ptr<ASConsole> console(new ASConsole(formatter));
4296 
4297 	// process command line and option files
4298 	// build the vectors fileNameVector, optionsVector, and fileOptionsVector
4299 	vector<string> argvOptions;
4300 	argvOptions = console->getArgvOptions(argc, argv);
4301 	console->processOptions(argvOptions);
4302 
4303 	// if no files have been given, use cin for input and cout for output
4304 	if (!console->fileNameVectorIsEmpty())
4305 		console->processFiles();
4306 	else
4307 		console->formatCinToCout();
4308 
4309 	return EXIT_SUCCESS;
4310 }
4311 
4312 #endif	// ASTYLE_LIB
4313