diff options
Diffstat (limited to 'src/tools/qdoc/yyindent.cpp')
-rw-r--r-- | src/tools/qdoc/yyindent.cpp | 1182 |
1 files changed, 0 insertions, 1182 deletions
diff --git a/src/tools/qdoc/yyindent.cpp b/src/tools/qdoc/yyindent.cpp deleted file mode 100644 index e48a847088..0000000000 --- a/src/tools/qdoc/yyindent.cpp +++ /dev/null @@ -1,1182 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the tools applications of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -/* - This file is a self-contained interactive indenter for C++ and Qt - Script. - - The general problem of indenting a C++ program is ill posed. On - the one hand, an indenter has to analyze programs written in a - free-form formal language that is best described in terms of - tokens, not characters, not lines. On the other hand, indentation - applies to lines and white space characters matter, and otherwise - the programs to indent are formally invalid in general, as they - are begin edited. - - The approach taken here works line by line. We receive a program - consisting of N lines or more, and we want to compute the - indentation appropriate for the Nth line. Lines beyond the Nth - lines are of no concern to us, so for simplicity we pretend the - program has exactly N lines and we call the Nth line the "bottom - line". Typically, we have to indent the bottom line when it's - still empty, so we concentrate our analysis on the N - 1 lines - that precede. - - By inspecting the (N - 1)-th line, the (N - 2)-th line, ... - backwards, we determine the kind of the bottom line and indent it - accordingly. - - * The bottom line is a comment line. See - bottomLineStartsInCComment() and - indentWhenBottomLineStartsInCComment(). - * The bottom line is a continuation line. See isContinuationLine() - and indentForContinuationLine(). - * The bottom line is a standalone line. See - indentForStandaloneLine(). - - Certain tokens that influence the indentation, notably braces, - are looked for in the lines. This is done by simple string - comparison, without a real tokenizer. Confusing constructs such - as comments and string literals are removed beforehand. -*/ - -#include <qregexp.h> -#include <qstringlist.h> - -QT_BEGIN_NAMESPACE - -/* qmake ignore Q_OBJECT */ - -/* - The indenter avoids getting stuck in almost infinite loops by - imposing arbitrary limits on the number of lines it analyzes when - looking for a construct. - - For example, the indenter never considers more than BigRoof lines - backwards when looking for the start of a C-style comment. -*/ -static const int SmallRoof = 40; -static const int BigRoof = 400; - -/* - The indenter supports a few parameters: - - * ppHardwareTabSize is the size of a '\t' in your favorite editor. - * ppIndentSize is the size of an indentation, or software tab - size. - * ppContinuationIndentSize is the extra indent for a continuation - line, when there is nothing to align against on the previous - line. - * ppCommentOffset is the indentation within a C-style comment, - when it cannot be picked up. -*/ - -static int ppHardwareTabSize = 8; -static int ppIndentSize = 4; -static int ppContinuationIndentSize = 8; - -static const int ppCommentOffset = 2; - -void setTabSize( int size ) -{ - ppHardwareTabSize = size; -} - -void setIndentSize( int size ) -{ - ppIndentSize = size; - ppContinuationIndentSize = 2 * size; -} - -static QRegExp *literal = 0; -static QRegExp *label = 0; -static QRegExp *inlineCComment = 0; -static QRegExp *braceX = 0; -static QRegExp *iflikeKeyword = 0; - -/* - Returns the first non-space character in the string t, or - QChar::Null if the string is made only of white space. -*/ -static QChar firstNonWhiteSpace( const QString& t ) -{ - int i = 0; - while ( i < (int) t.length() ) { - if ( !t[i].isSpace() ) - return t[i]; - i++; - } - return QChar::Null; -} - -/* - Returns \c true if string t is made only of white space; otherwise - returns \c false. -*/ -static bool isOnlyWhiteSpace( const QString& t ) -{ - return firstNonWhiteSpace( t ).isNull(); -} - -/* - Assuming string t is a line, returns the column number of a given - index. Column numbers and index are identical for strings that don't - contain '\t's. -*/ -int columnForIndex( const QString& t, int index ) -{ - int col = 0; - if ( index > (int) t.length() ) - index = t.length(); - - for ( int i = 0; i < index; i++ ) { - if ( t[i] == QChar('\t') ) { - col = ( (col / ppHardwareTabSize) + 1 ) * ppHardwareTabSize; - } else { - col++; - } - } - return col; -} - -/* - Returns the indentation size of string t. -*/ -int indentOfLine( const QString& t ) -{ - return columnForIndex( t, t.indexOf(firstNonWhiteSpace(t)) ); -} - -/* - Replaces t[k] by ch, unless t[k] is '\t'. Tab characters are better - left alone since they break the "index equals column" rule. No - provisions are taken against '\n' or '\r', which shouldn't occur in - t anyway. -*/ -static inline void eraseChar( QString& t, int k, QChar ch ) -{ - if ( t[k] != '\t' ) - t[k] = ch; -} - -/* - Removes some nefast constructs from a code line and returns the - resulting line. -*/ -static QString trimmedCodeLine( const QString& t ) -{ - QString trimmed = t; - int k; - - /* - Replace character and string literals by X's, since they may - contain confusing characters (such as '{' and ';'). "Hello!" is - replaced by XXXXXXXX. The literals are rigourously of the same - length before and after; otherwise, we would break alignment of - continuation lines. - */ - k = 0; - while ( (k = trimmed.indexOf(*literal, k)) != -1 ) { - for ( int i = 0; i < literal->matchedLength(); i++ ) - eraseChar( trimmed, k + i, 'X' ); - k += literal->matchedLength(); - } - - /* - Replace inline C-style comments by spaces. Other comments are - handled elsewhere. - */ - k = 0; - while ( (k = trimmed.indexOf(*inlineCComment, k)) != -1 ) { - for ( int i = 0; i < inlineCComment->matchedLength(); i++ ) - eraseChar( trimmed, k + i, ' ' ); - k += inlineCComment->matchedLength(); - } - - /* - Replace goto and switch labels by whitespace, but be careful - with this case: - - foo1: bar1; - bar2; - */ - while ( trimmed.lastIndexOf(':') != -1 && trimmed.indexOf(*label) != -1 ) { - QString cap1 = label->cap( 1 ); - int pos1 = label->pos( 1 ); - int stop = cap1.length(); - - if ( pos1 + stop < (int) trimmed.length() && ppIndentSize < stop ) - stop = ppIndentSize; - - int i = 0; - while ( i < stop ) { - eraseChar( trimmed, pos1 + i, ' ' ); - i++; - } - while ( i < (int) cap1.length() ) { - eraseChar( trimmed, pos1 + i, ';' ); - i++; - } - } - - /* - Remove C++-style comments. - */ - k = trimmed.indexOf( "//" ); - if ( k != -1 ) - trimmed.truncate( k ); - - return trimmed; -} - -/* - Returns '(' if the last parenthesis is opening, ')' if it is - closing, and QChar::Null if there are no parentheses in t. -*/ -static inline QChar lastParen( const QString& t ) -{ - int i = t.length(); - while ( i > 0 ) { - i--; - if ( t[i] == QChar('(') || t[i] == QChar(')') ) - return t[i]; - } - return QChar::Null; -} - -/* - Returns \c true if typedIn the same as okayCh or is null; otherwise - returns \c false. -*/ -static inline bool okay( QChar typedIn, QChar okayCh ) -{ - return typedIn == QChar::Null || typedIn == okayCh; -} - -/* - The "linizer" is a group of functions and variables to iterate - through the source code of the program to indent. The program is - given as a list of strings, with the bottom line being the line - to indent. The actual program might contain extra lines, but - those are uninteresting and not passed over to us. -*/ - -struct LinizerState -{ - QString line; - int braceDepth; - bool leftBraceFollows; - - QStringList::ConstIterator iter; - bool inCComment; - bool pendingRightBrace; -}; - -static QStringList *yyProgram = 0; -static LinizerState *yyLinizerState = 0; - -// shorthands -static const QString *yyLine = 0; -static const int *yyBraceDepth = 0; -static const bool *yyLeftBraceFollows = 0; - -/* - Saves and restores the state of the global linizer. This enables - backtracking. -*/ -#define YY_SAVE() \ - LinizerState savedState = *yyLinizerState -#define YY_RESTORE() \ - *yyLinizerState = savedState - -/* - Advances to the previous line in yyProgram and update yyLine - accordingly. yyLine is cleaned from comments and other damageable - constructs. Empty lines are skipped. -*/ -static bool readLine() -{ - int k; - - yyLinizerState->leftBraceFollows = - ( firstNonWhiteSpace(yyLinizerState->line) == QChar('{') ); - - do { - if ( yyLinizerState->iter == yyProgram->constBegin() ) { - yyLinizerState->line.clear(); - return false; - } - - --yyLinizerState->iter; - yyLinizerState->line = *yyLinizerState->iter; - - yyLinizerState->line = trimmedCodeLine( yyLinizerState->line ); - - /* - Remove C-style comments that span multiple lines. If the - bottom line starts in a C-style comment, we are not aware - of that and eventually yyLine will contain a slash-aster. - - Notice that both if's can be executed, since - yyLinizerState->inCComment is potentially set to false in - the first if. The order of the if's is also important. - */ - - if ( yyLinizerState->inCComment ) { - QString slashAster( "/*" ); - - k = yyLinizerState->line.indexOf( slashAster ); - if ( k == -1 ) { - yyLinizerState->line.clear(); - } else { - yyLinizerState->line.truncate( k ); - yyLinizerState->inCComment = false; - } - } - - if ( !yyLinizerState->inCComment ) { - QString asterSlash( "*/" ); - - k = yyLinizerState->line.indexOf( asterSlash ); - if ( k != -1 ) { - for ( int i = 0; i < k + 2; i++ ) - eraseChar( yyLinizerState->line, i, ' ' ); - yyLinizerState->inCComment = true; - } - } - - /* - Remove preprocessor directives. - */ - k = 0; - while ( k < (int) yyLinizerState->line.length() ) { - QChar ch = yyLinizerState->line[k]; - if ( ch == QChar('#') ) { - yyLinizerState->line.clear(); - } else if ( !ch.isSpace() ) { - break; - } - k++; - } - - /* - Remove trailing spaces. - */ - k = yyLinizerState->line.length(); - while ( k > 0 && yyLinizerState->line[k - 1].isSpace() ) - k--; - yyLinizerState->line.truncate( k ); - - /* - '}' increment the brace depth and '{' decrements it and not - the other way around, as we are parsing backwards. - */ - yyLinizerState->braceDepth += - yyLinizerState->line.count( '}' ) - - yyLinizerState->line.count( '{' ); - - /* - We use a dirty trick for - - } else ... - - We don't count the '}' yet, so that it's more or less - equivalent to the friendly construct - - } - else ... - */ - if ( yyLinizerState->pendingRightBrace ) - yyLinizerState->braceDepth++; - yyLinizerState->pendingRightBrace = - ( yyLinizerState->line.indexOf(*braceX) == 0 ); - if ( yyLinizerState->pendingRightBrace ) - yyLinizerState->braceDepth--; - } while ( yyLinizerState->line.isEmpty() ); - - return true; -} - -/* - Resets the linizer to its initial state, with yyLine containing the - line above the bottom line of the program. -*/ -static void startLinizer() -{ - yyLinizerState->braceDepth = 0; - yyLinizerState->inCComment = false; - yyLinizerState->pendingRightBrace = false; - - yyLine = &yyLinizerState->line; - yyBraceDepth = &yyLinizerState->braceDepth; - yyLeftBraceFollows = &yyLinizerState->leftBraceFollows; - - yyLinizerState->iter = yyProgram->constEnd(); - --yyLinizerState->iter; - yyLinizerState->line = *yyLinizerState->iter; - readLine(); -} - -/* - Returns \c true if the start of the bottom line of yyProgram (and - potentially the whole line) is part of a C-style comment; - otherwise returns \c false. -*/ -static bool bottomLineStartsInCComment() -{ - QString slashAster( "/*" ); - QString asterSlash( "*/" ); - - /* - We could use the linizer here, but that would slow us down - terribly. We are better to trim only the code lines we need. - */ - QStringList::ConstIterator p = yyProgram->constEnd(); - --p; // skip bottom line - - for ( int i = 0; i < BigRoof; i++ ) { - if ( p == yyProgram->constBegin() ) - return false; - --p; - - if ( (*p).indexOf(slashAster) != -1 || (*p).indexOf(asterSlash) != -1 ) { - QString trimmed = trimmedCodeLine( *p ); - - if ( trimmed.indexOf(slashAster) != -1 ) { - return true; - } else if ( trimmed.indexOf(asterSlash) != -1 ) { - return false; - } - } - } - return false; -} - -/* - Returns the recommended indent for the bottom line of yyProgram - assuming that it starts in a C-style comment, a condition that is - tested elsewhere. - - Essentially, we're trying to align against some text on the - previous line. -*/ -static int indentWhenBottomLineStartsInCComment() -{ - int k = yyLine->lastIndexOf( "/*" ); - if ( k == -1 ) { - /* - We found a normal text line in a comment. Align the - bottom line with the text on this line. - */ - return indentOfLine( *yyLine ); - } else { - /* - The C-style comment starts on this line. If there is - text on the same line, align with it. Otherwise, align - with the slash-aster plus a given offset. - */ - int indent = columnForIndex( *yyLine, k ); - k += 2; - while ( k < (int) yyLine->length() ) { - if ( !(*yyLine)[k].isSpace() ) - return columnForIndex( *yyLine, k ); - k++; - } - return indent + ppCommentOffset; - } -} - -/* - A function called match...() modifies the linizer state. If it - returns \c true, yyLine is the top line of the matched construct; - otherwise, the linizer is left in an unknown state. - - A function called is...() keeps the linizer state intact. -*/ - -/* - Returns \c true if the current line (and upwards) forms a braceless - control statement; otherwise returns \c false. - - The first line of the following example is a "braceless control - statement": - - if ( x ) - y; -*/ -static bool matchBracelessControlStatement() -{ - int delimDepth = 0; - - if ( yyLine->endsWith("else") ) - return true; - - if ( !yyLine->endsWith(QLatin1Char(')')) ) - return false; - - for ( int i = 0; i < SmallRoof; i++ ) { - int j = yyLine->length(); - while ( j > 0 ) { - j--; - QChar ch = (*yyLine)[j]; - - switch ( ch.unicode() ) { - case ')': - delimDepth++; - break; - case '(': - delimDepth--; - if ( delimDepth == 0 ) { - if ( yyLine->indexOf(*iflikeKeyword) != -1 ) { - /* - We have - - if ( x ) - y - - "if ( x )" is not part of the statement - "y". - */ - return true; - } - } - if ( delimDepth == -1 ) { - /* - We have - - if ( (1 + - 2) - - and not - - if ( 1 + - 2 ) - */ - return false; - } - break; - case '{': - case '}': - case ';': - /* - We met a statement separator, but not where we - expected it. What follows is probably a weird - continuation line. Be careful with ';' in for, - though. - */ - if ( ch != QChar(';') || delimDepth == 0 ) - return false; - } - } - - if ( !readLine() ) - break; - } - return false; -} - -/* - Returns \c true if yyLine is an unfinished line; otherwise returns - false. - - In many places we'll use the terms "standalone line", "unfinished - line" and "continuation line". The meaning of these should be - evident from this code example: - - a = b; // standalone line - c = d + // unfinished line - e + // unfinished continuation line - f + // unfinished continuation line - g; // continuation line -*/ -static bool isUnfinishedLine() -{ - bool unf = false; - - YY_SAVE(); - - if ( yyLine->isEmpty() ) - return false; - - QChar lastCh = (*yyLine)[(int) yyLine->length() - 1]; - if ( QString("{};").indexOf(lastCh) == -1 && !yyLine->endsWith("...") ) { - /* - It doesn't end with ';' or similar. If it's neither - "Q_OBJECT" nor "if ( x )", it must be an unfinished line. - */ - unf = ( yyLine->indexOf("Q_OBJECT") == -1 && - !matchBracelessControlStatement() ); - } else if ( lastCh == QChar(';') ) { - if ( lastParen(*yyLine) == QChar('(') ) { - /* - Exception: - - for ( int i = 1; i < 10; - */ - unf = true; - } else if ( readLine() && yyLine->endsWith(QLatin1Char(';')) && - lastParen(*yyLine) == QChar('(') ) { - /* - Exception: - - for ( int i = 1; - i < 10; - */ - unf = true; - } - } - - YY_RESTORE(); - return unf; -} - -/* - Returns \c true if yyLine is a continuation line; otherwise returns - false. -*/ -static bool isContinuationLine() -{ - bool cont = false; - - YY_SAVE(); - if ( readLine() ) - cont = isUnfinishedLine(); - YY_RESTORE(); - return cont; -} - -/* - Returns the recommended indent for the bottom line of yyProgram, - assuming it's a continuation line. - - We're trying to align the continuation line against some parenthesis - or other bracked left opened on a previous line, or some interesting - operator such as '='. -*/ -static int indentForContinuationLine() -{ - int braceDepth = 0; - int delimDepth = 0; - - bool leftBraceFollowed = *yyLeftBraceFollows; - - for ( int i = 0; i < SmallRoof; i++ ) { - int hook = -1; - - int j = yyLine->length(); - while ( j > 0 && hook < 0 ) { - j--; - QChar ch = (*yyLine)[j]; - - switch ( ch.unicode() ) { - case ')': - case ']': - delimDepth++; - break; - case '}': - braceDepth++; - break; - case '(': - case '[': - delimDepth--; - /* - An unclosed delimiter is a good place to align at, - at least for some styles (including Qt's). - */ - if ( delimDepth == -1 ) - hook = j; - break; - case '{': - braceDepth--; - /* - A left brace followed by other stuff on the same - line is typically for an enum or an initializer. - Such a brace must be treated just like the other - delimiters. - */ - if ( braceDepth == -1 ) { - if ( j < (int) yyLine->length() - 1 ) { - hook = j; - } else { - return 0; // shouldn't happen - } - } - break; - case '=': - /* - An equal sign is a very natural alignment hook - because it's usually the operator with the lowest - precedence in statements it appears in. Case in - point: - - int x = 1 + - 2; - - However, we have to beware of constructs such as - default arguments and explicit enum constant - values: - - void foo( int x = 0, - int y = 0 ); - - And not - - void foo( int x = 0, - int y = 0 ); - - These constructs are caracterized by a ',' at the - end of the unfinished lines or by unbalanced - parentheses. - */ - if ( QString("!=<>").indexOf((*yyLine)[j - 1]) == -1 && - (*yyLine)[j + 1] != '=' ) { - if ( braceDepth == 0 && delimDepth == 0 && - j < (int) yyLine->length() - 1 && - !yyLine->endsWith(QLatin1Char(',')) && - (yyLine->contains('(') == yyLine->contains(')')) ) - hook = j; - } - } - } - - if ( hook >= 0 ) { - /* - Yes, we have a delimiter or an operator to align - against! We don't really align against it, but rather - against the following token, if any. In this example, - the following token is "11": - - int x = ( 11 + - 2 ); - - If there is no such token, we use a continuation indent: - - static QRegExp foo( QString( - "foo foo foo foo foo foo foo foo foo") ); - */ - hook++; - while ( hook < (int) yyLine->length() ) { - if ( !(*yyLine)[hook].isSpace() ) - return columnForIndex( *yyLine, hook ); - hook++; - } - return indentOfLine( *yyLine ) + ppContinuationIndentSize; - } - - if ( braceDepth != 0 ) - break; - - /* - The line's delimiters are balanced. It looks like a - continuation line or something. - */ - if ( delimDepth == 0 ) { - if ( leftBraceFollowed ) { - /* - We have - - int main() - { - - or - - Bar::Bar() - : Foo( x ) - { - - The "{" should be flush left. - */ - if ( !isContinuationLine() ) - return indentOfLine( *yyLine ); - } else if ( isContinuationLine() || yyLine->endsWith(QLatin1Char(',')) ) { - /* - We have - - x = a + - b + - c; - - or - - int t[] = { - 1, 2, 3, - 4, 5, 6 - - The "c;" should fall right under the "b +", and the - "4, 5, 6" right under the "1, 2, 3,". - */ - return indentOfLine( *yyLine ); - } else { - /* - We have - - stream << 1 + - 2; - - We could, but we don't, try to analyze which - operator has precedence over which and so on, to - obtain the excellent result - - stream << 1 + - 2; - - We do have a special trick above for the assignment - operator above, though. - */ - return indentOfLine( *yyLine ) + ppContinuationIndentSize; - } - } - - if ( !readLine() ) - break; - } - return 0; -} - -/* - Returns the recommended indent for the bottom line of yyProgram if - that line is standalone (or should be indented likewise). - - Indenting a standalone line is tricky, mostly because of braceless - control statements. Grossly, we are looking backwards for a special - line, a "hook line", that we can use as a starting point to indent, - and then modify the indentation level according to the braces met - along the way to that hook. - - Let's consider a few examples. In all cases, we want to indent the - bottom line. - - Example 1: - - x = 1; - y = 2; - - The hook line is "x = 1;". We met 0 opening braces and 0 closing - braces. Therefore, "y = 2;" inherits the indent of "x = 1;". - - Example 2: - - if ( x ) { - y; - - The hook line is "if ( x ) {". No matter what precedes it, "y;" has - to be indented one level deeper than the hook line, since we met one - opening brace along the way. - - Example 3: - - if ( a ) - while ( b ) { - c; - } - d; - - To indent "d;" correctly, we have to go as far as the "if ( a )". - Compare with - - if ( a ) { - while ( b ) { - c; - } - d; - - Still, we're striving to go back as little as possible to - accommodate people with irregular indentation schemes. A hook line - near at hand is much more reliable than a remote one. -*/ -static int indentForStandaloneLine() -{ - for ( int i = 0; i < SmallRoof; i++ ) { - if ( !*yyLeftBraceFollows ) { - YY_SAVE(); - - if ( matchBracelessControlStatement() ) { - /* - The situation is this, and we want to indent "z;": - - if ( x && - y ) - z; - - yyLine is "if ( x &&". - */ - return indentOfLine( *yyLine ) + ppIndentSize; - } - YY_RESTORE(); - } - - if ( yyLine->endsWith(QLatin1Char(';')) || yyLine->contains('{') ) { - /* - The situation is possibly this, and we want to indent - "z;": - - while ( x ) - y; - z; - - We return the indent of "while ( x )". In place of "y;", - any arbitrarily complex compound statement can appear. - */ - - if ( *yyBraceDepth > 0 ) { - do { - if ( !readLine() ) - break; - } while ( *yyBraceDepth > 0 ); - } - - LinizerState hookState; - - while ( isContinuationLine() ) - readLine(); - hookState = *yyLinizerState; - - readLine(); - if ( *yyBraceDepth <= 0 ) { - do { - if ( !matchBracelessControlStatement() ) - break; - hookState = *yyLinizerState; - } while ( readLine() ); - } - - *yyLinizerState = hookState; - - while ( isContinuationLine() ) - readLine(); - - /* - Never trust lines containing only '{' or '}', as some - people (Richard M. Stallman) format them weirdly. - */ - if ( yyLine->trimmed().length() > 1 ) - return indentOfLine( *yyLine ) - *yyBraceDepth * ppIndentSize; - } - - if ( !readLine() ) - return -*yyBraceDepth * ppIndentSize; - } - return 0; -} - -/* - Constructs global variables used by the indenter. -*/ -static void initializeIndenter() -{ - literal = new QRegExp( "([\"'])(?:\\\\.|[^\\\\])*\\1" ); - literal->setMinimal( true ); - label = new QRegExp( - "^\\s*((?:case\\b([^:]|::)+|[a-zA-Z_0-9]+)(?:\\s+slots)?:)(?!:)" ); - inlineCComment = new QRegExp( "/\\*.*\\*/" ); - inlineCComment->setMinimal( true ); - braceX = new QRegExp( "^\\s*\\}\\s*(?:else|catch)\\b" ); - iflikeKeyword = new QRegExp( "\\b(?:catch|do|for|if|while)\\b" ); - - yyLinizerState = new LinizerState; -} - -/* - Destroys global variables used by the indenter. -*/ -static void terminateIndenter() -{ - delete literal; - delete label; - delete inlineCComment; - delete braceX; - delete iflikeKeyword; - delete yyLinizerState; -} - -/* - Returns the recommended indent for the bottom line of program. - Unless null, typedIn stores the character of yyProgram that - triggered reindentation. - - This function works better if typedIn is set properly; it is - slightly more conservative if typedIn is completely wild, and - slighly more liberal if typedIn is always null. The user might be - annoyed by the liberal behavior. -*/ -int indentForBottomLine( const QStringList& program, QChar typedIn ) -{ - if ( program.isEmpty() ) - return 0; - - initializeIndenter(); - - yyProgram = new QStringList( program ); - startLinizer(); - - const QString& bottomLine = program.last(); - QChar firstCh = firstNonWhiteSpace( bottomLine ); - int indent; - - if ( bottomLineStartsInCComment() ) { - /* - The bottom line starts in a C-style comment. Indent it - smartly, unless the user has already played around with it, - in which case it's better to leave her stuff alone. - */ - if ( isOnlyWhiteSpace(bottomLine) ) { - indent = indentWhenBottomLineStartsInCComment(); - } else { - indent = indentOfLine( bottomLine ); - } - } else if ( okay(typedIn, '#') && firstCh == QChar('#') ) { - /* - Preprocessor directives go flush left. - */ - indent = 0; - } else { - if ( isUnfinishedLine() ) { - indent = indentForContinuationLine(); - } else { - indent = indentForStandaloneLine(); - } - - if ( okay(typedIn, '}') && firstCh == QChar('}') ) { - /* - A closing brace is one level more to the left than the - code it follows. - */ - indent -= ppIndentSize; - } else if ( okay(typedIn, ':') ) { - QRegExp caseLabel( - "\\s*(?:case\\b(?:[^:]|::)+" - "|(?:public|protected|private|signals|default)(?:\\s+slots)?\\s*" - ")?:.*" ); - - if ( caseLabel.exactMatch(bottomLine) ) { - /* - Move a case label (or the ':' in front of a - constructor initialization list) one level to the - left, but only if the user did not play around with - it yet. Some users have exotic tastes in the - matter, and most users probably are not patient - enough to wait for the final ':' to format their - code properly. - - We don't attempt the same for goto labels, as the - user is probably the middle of "foo::bar". (Who - uses goto, anyway?) - */ - if ( indentOfLine(bottomLine) <= indent ) - indent -= ppIndentSize; - else - indent = indentOfLine( bottomLine ); - } - } - } - delete yyProgram; - terminateIndenter(); - return qMax( 0, indent ); -} - -QT_END_NAMESPACE - -#ifdef Q_TEST_YYINDENT -/* - Test driver. -*/ - -#include <qfile.h> -#include <qtextstream.h> - -#include <errno.h> - -QT_BEGIN_NAMESPACE - -static QString fileContents( const QString& fileName ) -{ - QFile f( fileName ); - if ( !f.open(QFile::ReadOnly) ) { - qWarning( "yyindent error: Cannot open file '%s' for reading: %s", - fileName.toLatin1().data(), strerror(errno) ); - return QString(); - } - - QTextStream t( &f ); - QString contents = t.read(); - f.close(); - if ( contents.isEmpty() ) - qWarning( "yyindent error: File '%s' is empty", fileName.toLatin1().data() ); - return contents; -} - -QT_END_NAMESPACE - -int main( int argc, char **argv ) -{ - QT_USE_NAMESPACE - - if ( argc != 2 ) { - qWarning( "usage: yyindent file.cpp" ); - return 1; - } - - QString code = fileContents( argv[1] ); - QStringList program = QStringList::split( '\n', code, true ); - QStringList p; - QString out; - - while ( !program.isEmpty() && program.last().trimmed().isEmpty() ) - program.remove( program.fromLast() ); - - QStringList::ConstIterator line = program.constBegin(); - while ( line != program.constEnd() ) { - p.push_back( *line ); - QChar typedIn = firstNonWhiteSpace( *line ); - if ( p.last().endsWith(QLatin1Char(':')) ) - typedIn = ':'; - - int indent = indentForBottomLine( p, typedIn ); - - if ( !(*line).trimmed().isEmpty() ) { - for ( int j = 0; j < indent; j++ ) - out += QLatin1Char(' '); - out += (*line).trimmed(); - } - out += QLatin1Char('\n'); - ++line; - } - - while ( out.endsWith(QLatin1Char('\n')) ) - out.truncate( out.length() - 1 ); - - printf( "%s\n", out.toLatin1().data() ); - return 0; -} - -#endif // Q_TEST_YYINDENT |