| 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 | |