diff --git a/src/ASBeautifier.cpp b/src/ASBeautifier.cpp index 61bf441..72f0cc5 100644 --- a/src/ASBeautifier.cpp +++ b/src/ASBeautifier.cpp @@ -180,6 +180,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) isInStatement = other.isInStatement; isInHeader = other.isInHeader; isInTemplate = other.isInTemplate; + isInTemplateInstantiation = other.isInTemplateInstantiation; isInDefine = other.isInDefine; isInDefineDefinition = other.isInDefineDefinition; classIndent = other.classIndent; @@ -226,6 +227,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) shouldAlignMethodColon = other.shouldAlignMethodColon; shouldIndentPreprocDefine = other.shouldIndentPreprocDefine; shouldIndentPreprocConditional = other.shouldIndentPreprocConditional; + potentialTemplateDisambiguator = other.potentialTemplateDisambiguator; indentCount = other.indentCount; spaceIndentCount = other.spaceIndentCount; spaceIndentObjCMethodDefinition = other.spaceIndentObjCMethodDefinition; @@ -252,6 +254,7 @@ ASBeautifier::ASBeautifier(const ASBeautifier& other) : ASBase(other) currentNonSpaceCh = other.currentNonSpaceCh; currentNonLegalCh = other.currentNonLegalCh; prevNonLegalCh = other.prevNonLegalCh; + lineFirstChar = other.lineFirstChar; } /** @@ -344,7 +347,9 @@ void ASBeautifier::init(ASSourceIterator* iter) isInLet = false; isInHeader = false; isInTemplate = false; + isInTemplateInstantiation = false; isInConditional = false; + potentialTemplateDisambiguator = false; indentCount = 0; spaceIndentCount = 0; @@ -365,6 +370,7 @@ void ASBeautifier::init(ASSourceIterator* iter) prevNonLegalCh = '{'; currentNonLegalCh = '{'; quoteChar = ' '; + lineFirstChar = ' '; probationHeader = NULL; lastLineHeader = NULL; backslashEndsPrevLine = false; @@ -879,6 +885,7 @@ string ASBeautifier::beautify(const string& originalLine) haveLineContinuationChar = false; lineOpeningBlocksNum = 0; lineClosingBlocksNum = 0; + lineFirstChar = ' '; if (isImmediatelyPostObjCMethodDefinition) clearObjCMethodDefinitionAlignment(); @@ -920,6 +927,7 @@ string ASBeautifier::beautify(const string& originalLine) line = trim(originalLine); if (line.length() > 0) { + lineFirstChar = line[0]; if (line[0] == '{') lineBeginsWithOpenBracket = true; else if (line[0] == '}') @@ -1253,10 +1261,12 @@ void ASBeautifier::registerInStatementIndent(const string& line, int i, int spac int tabIncrementIn, int minIndent, bool updateParenStack) { int remainingCharNum = line.length() - i; - int nextNonWSChar = getNextProgramCharDistance(line, i); + // Get the next program char distance to determine if the remaining + // text is comment-only + int nextProgramChar = getNextProgramCharDistance(line, i); // if indent is around the last char in the line, indent instead one indent from the previous indent - if (nextNonWSChar == remainingCharNum) + if (nextProgramChar == remainingCharNum) { int previousIndent = spaceTabCount_; if (!inStatementIndentStack->empty()) @@ -1271,6 +1281,13 @@ void ASBeautifier::registerInStatementIndent(const string& line, int i, int spac return; } + // The next line should be aligned with the next non-whitespace character. + // This character could be a beginning of a comment + int nextNonWSChar = 1; + size_t nextCharPos = line.find_first_not_of(" \t", i + 1); + if (nextCharPos != string::npos) + nextNonWSChar = nextCharPos - i; + if (updateParenStack) parenIndentStack->push_back(i + spaceTabCount_ - horstmannIndentInStatement); @@ -2097,27 +2114,34 @@ void ASBeautifier::computePreliminaryIndentation() ++indentCount; isInSwitch = true; } - } // end of for loop if (isInClassHeader) { if (!isJavaStyle()) isInClassHeaderTab = true; - if (lineOpensWithLineComment || lineStartsInComment || lineOpensWithComment) - { - if (!lineBeginsWithOpenBracket) - --indentCount; - if (!inStatementIndentStack->empty()) - spaceIndentCount -= inStatementIndentStack->back(); - } - else if (blockIndent) + if (blockIndent) { if (!lineBeginsWithOpenBracket) ++indentCount; } } + if (isInTemplate || isInTemplateInstantiation) + { + // Use symmetrical layout for closing brace in template argument list: + // + // template + // < + // class Argument + // > + if (lineFirstChar == '>' && !lineStartsInComment) + { + if (!inStatementIndentStack->empty()) + spaceIndentCount -= inStatementIndentStack->back(); + } + } + if (isInClassInitializer || isInEnumTypeID) { indentCount += classInitializerIndents; @@ -2334,7 +2358,6 @@ void ASBeautifier::parseCurrentLine(const string& line) bool isInOperator = false; bool isSpecialChar = false; bool haveCaseIndent = false; - bool haveAssignmentThisLine = false; bool closingBracketReached = false; bool previousLineProbation = (probationHeader != NULL); char ch = ' '; @@ -2549,6 +2572,14 @@ void ASBeautifier::parseCurrentLine(const string& line) probationHeader = NULL; } + if (potentialTemplateDisambiguator) + { + // Disable the template disambiguator flag if the next word + // is not "template" + if (ch != 't' || getNextWord(line, i - 1) != AS_TEMPLATE) + potentialTemplateDisambiguator = false; + } + prevNonSpaceCh = currentNonSpaceCh; currentNonSpaceCh = ch; if (!isLegalNameChar(ch) && ch != ',' && ch != ';') @@ -2565,27 +2596,66 @@ void ASBeautifier::parseCurrentLine(const string& line) else currentHeader = NULL; - if (isCStyle() && isInTemplate + if (isCStyle() && (ch == '<' || ch == '>') && !(line.length() > i + 1 && line.compare(i, 2, ">=") == 0)) { - if (ch == '<') - { - ++templateDepth; - inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); - registerInStatementIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true); - } - else if (ch == '>') - { - popLastInStatementIndent(); - if (--templateDepth <= 0) - { - ch = ';'; - isInTemplate = false; - templateDepth = 0; - } - } - } + if (isInTemplate) + { + if (ch == '<') + { + ++templateDepth; + inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); + registerInStatementIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true); + } + else if (ch == '>') + { + popLastInStatementIndent(); + if (--templateDepth <= 0) + { + ch = ';'; + isInTemplate = false; + templateDepth = 0; + } + } + } + else if (parenDepth == 0 && !isInClassHeader) + { + // A template instantiation cannot start with << + if (ch == '<' + && !(line.length() > i + 1 && line.compare(i, 2, "<<") == 0)) + { + if (!isInStatement && templateDepth == 0) + { + isInTemplateInstantiation = true; + } + + ++templateDepth; + + if (isInTemplateInstantiation) + { + inStatementIndentStackSizeStack->push_back(inStatementIndentStack->size()); + registerInStatementIndent(line, i, spaceIndentCount, tabIncrementIn, 0, true); + isInStatement = true; + } + } + else if (ch == '>' && templateDepth > 0) + { + if (isInTemplateInstantiation + && !inStatementIndentStackSizeStack->empty()) + { + popLastInStatementIndent(); + } + if (--templateDepth <= 0) + { + isInTemplateInstantiation = false; + templateDepth = 0; + } + } + } + } + + // handle parentheses if (ch == '(' || ch == '[' || ch == ')' || ch == ']') @@ -2775,7 +2845,13 @@ void ASBeautifier::parseCurrentLine(const string& line) if (lineBeginsWithOpenBracket || lineBeginsWithComma) spaceIndentCount = 0; } - else + // Do not zero the spaceIndentCount for the current line + // if we are within a statement. This is useful for lambda + // expressions in multiline statements: + // + // std::generate(data.begin(), data.end(), + // [&]() { return randval(engine); }); + else if (!isInStatement || lineBeginsWithOpenBracket) spaceIndentCount = 0; } @@ -2819,6 +2895,18 @@ void ASBeautifier::parseCurrentLine(const string& line) && ASBeautifier::peekNextChar(line, i + (*newHeader).length() - 1) != '(') newHeader = NULL; + // The "template" disambiguator for dependent names should not + // be recognized as an actual template header. For example: + // T::template foo() + // s.template foo(); + // this->template foo(); + if (isCStyle() && newHeader == &AS_TEMPLATE + && (potentialTemplateDisambiguator || prevNonSpaceCh == '.')) + { + newHeader = NULL; + potentialTemplateDisambiguator = false; + } + if (newHeader != NULL) { // if we reached here, then this is a header... @@ -2979,7 +3067,6 @@ void ASBeautifier::parseCurrentLine(const string& line) if (isSharpStyle() && findKeyword(line, i, AS_LET)) isInLet = true; - } // isPotentialHeader if (ch == '?') @@ -2991,6 +3078,9 @@ void ASBeautifier::parseCurrentLine(const string& line) if (line.length() > i + 1 && line[i + 1] == ':') // look for :: { ++i; + // The next word might be a template disambiguator like + // T::template foo() + potentialTemplateDisambiguator = true; continue; } else if (isInQuestion) @@ -3075,10 +3165,13 @@ void ASBeautifier::parseCurrentLine(const string& line) } if ((ch == ';' || (parenDepth > 0 && ch == ',')) && !inStatementIndentStackSizeStack->empty()) - while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0) + { + while ((int) inStatementIndentStackSizeStack->back() + (parenDepth > 0 ? 1 : 0) < (int) inStatementIndentStack->size()) + { inStatementIndentStack->pop_back(); - + } + } else if (ch == ',' && isInEnum && isNonInStatementArray && !inStatementIndentStack->empty()) inStatementIndentStack->pop_back(); @@ -3103,7 +3196,8 @@ void ASBeautifier::parseCurrentLine(const string& line) // do nothing for now } // register indent at second word on the line - else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer) + else if (!isInTemplate && !isInClassHeaderTab && !isInClassInitializer + && !isInClassHeader) { int prevWord = getInStatementIndentComma(line, i); int inStatementIndent = prevWord + spaceIndentCount + tabIncrementIn; @@ -3223,7 +3317,17 @@ void ASBeautifier::parseCurrentLine(const string& line) } if (parenDepth == 0 && ch == ';') + { isInStatement = false; + isInTemplateInstantiation = false; + templateDepth = 0; + + // This is the end of a statement, so the inStatementIndentStack + // should be reset to its default state + while (inStatementIndentStackSizeStack->size() > 1) + inStatementIndentStackSizeStack->pop_back(); + inStatementIndentStack->clear(); + } if (isInObjCMethodDefinition) isImmediatelyPostObjCMethodDefinition = true; @@ -3400,7 +3504,8 @@ void ASBeautifier::parseCurrentLine(const string& line) if (foundNonAssignmentOp == &AS_LAMBDA) foundPreCommandHeader = true; - if (isInTemplate && foundNonAssignmentOp == &AS_GR_GR) + if ((isInTemplate || isInTemplateInstantiation) + && foundNonAssignmentOp == &AS_GR_GR) foundNonAssignmentOp = NULL; // Since findHeader's boundary checking was not used above, it is possible @@ -3420,10 +3525,18 @@ void ASBeautifier::parseCurrentLine(const string& line) if (foundNonAssignmentOp->length() > 1) i += foundNonAssignmentOp->length() - 1; + // The "template" disambiguator for dependent names should not + // be recognized as an actual template header. For example: + // this->template foo(); + if (isCStyle() && foundNonAssignmentOp == &AS_ARROW) + { + potentialTemplateDisambiguator = true; + } + // For C++ input/output, operator<< and >> should be // aligned, if we are not in a statement already and // also not in the "operator<<(...)" header line - if (!isInOperator + if (!isInOperator && !isInClassHeader && inStatementIndentStack->empty() && isCStyle() && (foundNonAssignmentOp == &AS_GR_GR @@ -3447,23 +3560,8 @@ void ASBeautifier::parseCurrentLine(const string& line) if (!isInOperator && !isInTemplate && (!isNonInStatementArray || isInEnum)) { - // if multiple assignments, align on the previous word - if (foundAssignmentOp == &AS_ASSIGN - && prevNonSpaceCh != ']' // an array - && statementEndsWithComma(line, i)) - { - if (!haveAssignmentThisLine) // only one assignment indent per line - { - // register indent at previous word - haveAssignmentThisLine = true; - int prevWordIndex = getInStatementIndentAssign(line, i); - int inStatementIndent = prevWordIndex + spaceIndentCount + tabIncrementIn; - inStatementIndentStack->push_back(inStatementIndent); - isInStatement = true; - } - } // don't indent an assignment if 'let' - else if (isInLet) + if (isInLet) { isInLet = false; } @@ -3479,5 +3577,4 @@ void ASBeautifier::parseCurrentLine(const string& line) } } // end of for loop * end of for loop * end of for loop * end of for loop * end of for loop * } - } // end namespace astyle diff --git a/src/ASFormatter.cpp b/src/ASFormatter.cpp index c41ffe8..8933c1f 100644 --- a/src/ASFormatter.cpp +++ b/src/ASFormatter.cpp @@ -1209,6 +1209,64 @@ string ASFormatter::nextLine() } } // (isPotentialHeader && !isInTemplate) + if (currentChar == ':' + && previousChar != ':' // not part of '::' + && peekNextChar() != ':') // not part of '::' + { + if (isInCase) + { + isInCase = false; + if (shouldBreakOneLineStatements) + passedColon = true; + } + else if (isCStyle() // for C/C++ only + && isOkToBreakBlock(bracketTypeStack->back()) + && shouldBreakOneLineStatements + && !foundQuestionMark // not in a ?: sequence + && !foundPreDefinitionHeader // not in a definition block (e.g. class foo : public bar + && previousCommandChar != ')' // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...) + && !foundPreCommandHeader // not after a 'noexcept' + && !squareBracketCount // not in objC method call + && !isInObjCMethodDefinition // not objC '-' or '+' method + && !isInObjCInterface // not objC @interface + && !isInObjCSelector // not objC @selector + && !isDigit(peekNextChar()) // not a bit field + && !isInEnum // not an enum with a base type + && !isInAsm // not in extended assembler + && !isInAsmOneLine // not in extended assembler + && !isInAsmBlock) // not in extended assembler + { + passedColon = true; + } + + if (isCStyle() + && shouldPadMethodColon + && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector) + && !foundQuestionMark) // not in a ?: sequence + padObjCMethodColon(); + + if (isInObjCInterface) + { + appendSpacePad(); + if ((int) currentLine.length() > charNum + 1 && !isWhiteSpace(currentLine[charNum + 1])) + currentLine.insert(charNum + 1, " "); + } + + if (isClassInitializer()) + { + isInClassInitializer = true; + if (!isCharImmediatelyPostComment && !isCharImmediatelyPostLineComment) + { + // Attach colon to the constructor header and force a + // new line before the member initializer list + appendSpacePad(); + appendCurrentChar(false); + shouldBreakLineAtNextChar = true; + continue; + } + } + } + if (isInLineBreak) // OK to break line here { breakLine(); @@ -1255,53 +1313,6 @@ string ASFormatter::nextLine() resetEndOfStatement(); } - if (currentChar == ':' - && previousChar != ':' // not part of '::' - && peekNextChar() != ':') // not part of '::' - { - if (isInCase) - { - isInCase = false; - if (shouldBreakOneLineStatements) - passedColon = true; - } - else if (isCStyle() // for C/C++ only - && isOkToBreakBlock(bracketTypeStack->back()) - && shouldBreakOneLineStatements - && !foundQuestionMark // not in a ?: sequence - && !foundPreDefinitionHeader // not in a definition block (e.g. class foo : public bar - && previousCommandChar != ')' // not immediately after closing paren of a method header, e.g. ASFormatter::ASFormatter(...) : ASBeautifier(...) - && !foundPreCommandHeader // not after a 'noexcept' - && !squareBracketCount // not in objC method call - && !isInObjCMethodDefinition // not objC '-' or '+' method - && !isInObjCInterface // not objC @interface - && !isInObjCSelector // not objC @selector - && !isDigit(peekNextChar()) // not a bit field - && !isInEnum // not an enum with a base type - && !isInAsm // not in extended assembler - && !isInAsmOneLine // not in extended assembler - && !isInAsmBlock) // not in extended assembler - { - passedColon = true; - } - - if (isCStyle() - && shouldPadMethodColon - && (squareBracketCount > 0 || isInObjCMethodDefinition || isInObjCSelector) - && !foundQuestionMark) // not in a ?: sequence - padObjCMethodColon(); - - if (isInObjCInterface) - { - appendSpacePad(); - if ((int) currentLine.length() > charNum + 1 && !isWhiteSpace(currentLine[charNum + 1])) - currentLine.insert(charNum + 1, " "); - } - - if (isClassInitializer()) - isInClassInitializer = true; - } - if (currentChar == '?') foundQuestionMark = true; @@ -1406,7 +1417,6 @@ string ASFormatter::nextLine() } continue; - } // (isPotentialHeader && !isInTemplate) // determine if this is an Objective-C statement @@ -1592,7 +1602,6 @@ string ASFormatter::nextLine() } appendCurrentChar(); - } // end of while loop * end of while loop * end of while loop * end of while loop // return a beautified (i.e. correctly indented) line. @@ -2805,6 +2814,9 @@ bool ASFormatter::isPointerOrReference() const { if (previousNonWSChar == '>') return true; + // This is a logical expression in a pre-definition header + if (foundPreDefinitionHeader) + return false; string followingText = peekNextText(currentLine.substr(charNum + 2)); if (followingText.length() > 0 && followingText[0] == ')') return true; @@ -3564,7 +3576,7 @@ void ASFormatter::formatPointerOrReference(void) peekedChar = currentLine[nextChar]; } // check for cast - if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',') + if (peekedChar == ')' || peekedChar == '>' || peekedChar == ',' || peekedChar == '.') { formatPointerOrReferenceCast(); return; @@ -7272,5 +7284,4 @@ void ASFormatter::stripCommentPrefix() } } } - } // end namespace astyle diff --git a/src/astyle.h b/src/astyle.h index c910942..4af6a0d 100644 --- a/src/astyle.h +++ b/src/astyle.h @@ -279,7 +279,6 @@ protected: // functions definitions are at the end of ASResource.cpp bool isCharPotentialOperator(char ch) const; bool isDigitSeparator(const string& line, int i) const; char peekNextChar(const string& line, int i) const; - }; // Class ASBase //----------------------------------------------------------------------------- @@ -445,6 +444,7 @@ private: // variables bool isInStatement; bool isInHeader; bool isInTemplate; + bool isInTemplateInstantiation; bool isInDefine; bool isInDefineDefinition; bool classIndent; @@ -491,6 +491,7 @@ private: // variables bool foundPreCommandMacro; bool shouldAlignMethodColon; bool shouldIndentPreprocConditional; + bool potentialTemplateDisambiguator; int indentCount; int spaceIndentCount; int spaceIndentObjCMethodDefinition; @@ -517,6 +518,7 @@ private: // variables char currentNonSpaceCh; char currentNonLegalCh; char prevNonLegalCh; + char lineFirstChar; }; // Class ASBeautifier //----------------------------------------------------------------------------- @@ -591,7 +593,6 @@ private: // SQL variables bool nextLineIsDeclareIndent; // begin declare section indent is reached bool isInDeclareSection; // need to indent a declare section - }; // Class ASEnhancer //----------------------------------------------------------------------------- @@ -987,7 +988,6 @@ private: // inline functions // sort comparison functions for ASResource bool sortOnLength(const string* a, const string* b); bool sortOnName(const string* a, const string* b); - } // end of astyle namespace // end of astyle namespace -------------------------------------------------- diff --git a/src/astyle_main.cpp b/src/astyle_main.cpp index 16a0c4b..0ddb7d0 100644 --- a/src/astyle_main.cpp +++ b/src/astyle_main.cpp @@ -540,12 +540,21 @@ void ASConsole::formatFile(const string& fileName_) ASStreamIterator streamIterator(&in); formatter.init(&streamIterator); + // remove targetDirectory from filename if required by print + string displayName; + if (hasWildcard) + displayName = fileName_.substr(targetDirectory.length() + 1); + else + displayName = fileName_; + // format the file + int currentLine = 0; while (formatter.hasMoreLines()) { nextLine = formatter.nextLine(); out << nextLine; linesOut++; + currentLine++; if (formatter.hasMoreLines()) { setOutputEOL(lineEndFormat, streamIterator.getOutputEOL()); @@ -562,19 +571,28 @@ void ASConsole::formatFile(const string& fileName_) nextLine = formatter.nextLine(); out << nextLine; linesOut++; + currentLine++; streamIterator.saveLastInputLine(); } } - if (filesAreIdentical) + if (filesAreIdentical || printChanges) { if (streamIterator.checkForEmptyLine) { if (nextLine.find_first_not_of(" \t") != string::npos) + { + if (printChanges) + printChangedLine(fileName_, nextLine, currentLine); filesAreIdentical = false; + } } else if (!streamIterator.compareToInputBuffer(nextLine)) - filesAreIdentical = false; + { + if (printChanges) + printChangedLine(fileName_, nextLine, currentLine); + filesAreIdentical = false; + } streamIterator.checkForEmptyLine = false; } } @@ -585,19 +603,14 @@ void ASConsole::formatFile(const string& fileName_) filesAreIdentical = false; } - // remove targetDirectory from filename if required by print - string displayName; - if (hasWildcard) - displayName = fileName_.substr(targetDirectory.length() + 1); - else - displayName = fileName_; - // if file has changed, write the new file if (!filesAreIdentical || streamIterator.getLineEndChange(lineEndFormat)) { if (!isDryRun) writeFile(fileName_, encoding, out); printMsg(_("Formatted %s\n"), displayName); + if (printChanges) + printSeparatingLine(); filesFormatted++; } else @@ -610,6 +623,20 @@ void ASConsole::formatFile(const string& fileName_) assert(formatter.getChecksumDiff() == 0); } +void ASConsole::printChangedLine(const string& fileName, const string& line, int lineNumber) +{ + if (printChanges && !isQuiet) + { + // Print the filename, as this is the first change for file + if (filesAreIdentical) + { + printSeparatingLine(); + printf("Changes in %s\n", fileName.c_str()); + } + printf("%s(%5d): %s\n", fileName.c_str(), lineNumber, line.c_str()); + } +} + // build a vector of argv options // the program path argv[0] is excluded vector ASConsole::getArgvOptions(int argc, char** argv) const @@ -662,6 +689,10 @@ bool ASConsole::getIgnoreExcludeErrorsDisplay() const bool ASConsole::getIsDryRun() const { return isDryRun; } +// for unit testing +bool ASConsole::getPrintChanges() const +{ return printChanges; } + // for unit testing bool ASConsole::getIsFormattedOnly() const { return isFormattedOnly; } @@ -800,6 +831,9 @@ void ASConsole::setIsRecursive(bool state) void ASConsole::setIsDryRun(bool state) { isDryRun = state; } +void ASConsole::setPrintChanges(bool state) +{ printChanges = state; } + void ASConsole::setIsVerbose(bool state) { isVerbose = state; } @@ -1419,7 +1453,9 @@ void ASConsole::getFilePaths(string& filePath) fprintf(stderr, _("No file to process %s\n"), filePath.c_str()); if (hasWildcard && !isRecursive) fprintf(stderr, "%s\n", _("Did you intend to use --recursive")); - error(); + // Do not terminate if no match was found for this wildcard + if (!hasWildcard) + error(); } if (hasWildcard) @@ -2796,7 +2832,7 @@ void ASOptions::parseOption(const string& arg, const string& errorInfo) string maxIndentParam = getParam(arg, "M", "max-instatement-indent="); if (maxIndentParam.length() > 0) maxIndent = atoi(maxIndentParam.c_str()); - if (maxIndent < 40) + if (maxIndent < 2 * formatter.getIndentLength()) isOptionError(arg, errorInfo); else if (maxIndent > 120) isOptionError(arg, errorInfo); @@ -3137,6 +3173,10 @@ void ASOptions::parseOption(const string& arg, const string& errorInfo) { g_console->setIsDryRun(true); } + else if (isOption(arg, "print-changes")) + { + g_console->setPrintChanges(true); + } else if ( isOption(arg, "Z", "preserve-date") ) { g_console->setPreserveDate(true); @@ -3552,7 +3592,6 @@ size_t Utf8_16::utf16ToUtf8(char* utf16In, size_t inLen, bool isBigEndian, } //---------------------------------------------------------------------------- - } // end of astyle namespace //---------------------------------------------------------------------------- @@ -3807,8 +3846,16 @@ int main(int argc, char** argv) // process entries in the fileNameVector g_console->processFiles(); + int return_code = EXIT_SUCCESS; + if (g_console->getPrintChanges() && g_console->getFilesFormatted() > 0) + { + // Use the number of formatted files as a return code with the + // --print-changes option + return_code = g_console->getFilesFormatted(); + } + delete g_console; - return EXIT_SUCCESS; + return return_code; } #endif // ASTYLE_LIB diff --git a/src/astyle_main.h b/src/astyle_main.h index bfbc0e2..43d5fd2 100644 --- a/src/astyle_main.h +++ b/src/astyle_main.h @@ -232,6 +232,7 @@ private: // variables // command line options bool isRecursive; // recursive option bool isDryRun; // dry-run option + bool printChanges; // print-changes option bool noBackup; // suffix=none option bool preserveDate; // preserve-date option bool isVerbose; // verbose option @@ -307,6 +308,7 @@ public: // functions bool getIgnoreExcludeErrors() const; bool getIgnoreExcludeErrorsDisplay() const; bool getIsDryRun() const; + bool getPrintChanges() const; bool getIsFormattedOnly() const; bool getIsQuiet() const; bool getIsRecursive() const; @@ -325,6 +327,7 @@ public: // functions void setIgnoreExcludeErrors(bool state); void setIgnoreExcludeErrorsAndDisplay(bool state); void setIsDryRun(bool state); + void setPrintChanges(bool state); void setIsFormattedOnly(bool state); void setIsQuiet(bool state); void setIsRecursive(bool state); @@ -347,6 +350,7 @@ private: // functions ASConsole& operator=(ASConsole&); // not to be implemented void correctMixedLineEnds(ostringstream& out); void formatFile(const string& fileName_); + void printChangedLine(const string& fileName, const string& line, int lineNumber); string getCurrentDirectory(const string& fileName_) const; void getFileNames(const string& directory, const string& wildcard); void getFilePaths(string& filePath);