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