• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

Kate

kateregexpsearch.cpp

Go to the documentation of this file.
00001 /*  This file is part of the KDE libraries and the Kate part.
00002  *
00003  *  Copyright (C) 2010 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
00004  *  Copyright (C) 2007 Sebastian Pipping <webmaster@hartwork.org>
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Library General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Library General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU Library General Public License
00017  *  along with this library; see the file COPYING.LIB.  If not, write to
00018  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  *  Boston, MA 02110-1301, USA.
00020  */
00021 
00022 //BEGIN includes
00023 #include "kateregexpsearch.h"
00024 #include "kateregexp.h"
00025 
00026 #include <ktexteditor/document.h>
00027 //END  includes
00028 
00029 
00030 
00031 // Turn debug messages on/off here
00032 // #define FAST_DEBUG_ENABLE
00033 
00034 #ifdef FAST_DEBUG_ENABLE
00035 # define FAST_DEBUG(x) kDebug( 13020 ) << x
00036 #else
00037 # define FAST_DEBUG(x)
00038 #endif
00039 
00040 
00041 class KateRegExpSearch::ReplacementStream
00042 {
00043 public:
00044   struct counter {
00045     counter(int value, int minWidth)
00046       : value(value)
00047       , minWidth(minWidth)
00048     {}
00049 
00050     const int value;
00051     const int minWidth;
00052   };
00053 
00054   struct cap {
00055     cap(int n)
00056       : n(n)
00057     {}
00058 
00059     const int n;
00060   };
00061 
00062   enum CaseConversion {
00063     upperCase,      
00064     upperCaseFirst, 
00065     lowerCase,      
00066     lowerCaseFirst, 
00067     keepCase        
00068   };
00069 
00070 public:
00071   ReplacementStream(const QStringList &capturedTexts);
00072 
00073   QString str() const { return m_str; }
00074 
00075   ReplacementStream &operator<<(const QString &);
00076   ReplacementStream &operator<<(const counter &);
00077   ReplacementStream &operator<<(const cap &);
00078   ReplacementStream &operator<<(CaseConversion);
00079 
00080 private:
00081   const QStringList m_capturedTexts;
00082   CaseConversion m_caseConversion;
00083   QString m_str;
00084 };
00085 
00086 
00087 KateRegExpSearch::ReplacementStream::ReplacementStream(const QStringList &capturedTexts)
00088   : m_capturedTexts(capturedTexts)
00089   , m_caseConversion(keepCase)
00090 {
00091 }
00092 
00093 KateRegExpSearch::ReplacementStream &KateRegExpSearch::ReplacementStream::operator<<(const QString &str)
00094 {
00095     switch (m_caseConversion) {
00096     case upperCase:
00097         // Copy as uppercase
00098         m_str.append(str.toUpper());
00099         break;
00100 
00101     case upperCaseFirst:
00102         if (str.length() > 0) {
00103             m_str.append(str.at(0).toUpper());
00104             m_str.append(str.mid(1));
00105             m_caseConversion = keepCase;
00106         }
00107         break;
00108 
00109     case lowerCase:
00110         // Copy as lowercase
00111         m_str.append(str.toLower());
00112         break;
00113 
00114     case lowerCaseFirst:
00115         if (str.length() > 0) {
00116             m_str.append(str.at(0).toLower());
00117             m_str.append(str.mid(1));
00118             m_caseConversion = keepCase;
00119         }
00120         break;
00121 
00122     case keepCase: // FALLTHROUGH
00123     default:
00124         // Copy unmodified
00125         m_str.append(str);
00126         break;
00127 
00128     }
00129 
00130     return *this;
00131 }
00132 
00133 
00134 KateRegExpSearch::ReplacementStream &KateRegExpSearch::ReplacementStream::operator<<(const counter &c)
00135 {
00136   // Zero padded counter value
00137   m_str.append(QString("%1").arg(c.value, c.minWidth, 10, QLatin1Char('0')));
00138 
00139   return *this;
00140 }
00141 
00142 
00143 KateRegExpSearch::ReplacementStream &KateRegExpSearch::ReplacementStream::operator<<(const cap &cap)
00144 {
00145   if (0 <= cap.n && cap.n < m_capturedTexts.size()) {
00146       (*this) << m_capturedTexts[cap.n];
00147   } else {
00148       // Insert just the number to be consistent with QRegExp ("\c" becomes "c")
00149       m_str.append(QString::number(cap.n));
00150   }
00151 
00152   return *this;
00153 }
00154 
00155 
00156 KateRegExpSearch::ReplacementStream &KateRegExpSearch::ReplacementStream::operator<<(CaseConversion caseConversion)
00157 {
00158   m_caseConversion = caseConversion;
00159 
00160   return *this;
00161 }
00162 
00163 
00164 //BEGIN d'tor, c'tor
00165 //
00166 // KateSearch Constructor
00167 //
00168 KateRegExpSearch::KateRegExpSearch ( KTextEditor::Document *document, Qt::CaseSensitivity caseSensitivity )
00169 : m_document (document)
00170 , m_caseSensitivity (caseSensitivity)
00171 {
00172 }
00173 
00174 //
00175 // KateSearch Destructor
00176 //
00177 KateRegExpSearch::~KateRegExpSearch()
00178 {
00179 }
00180 
00181 
00182 // helper structs for captures re-construction
00183 struct TwoViewCursor {
00184   int index;
00185   int openLine;
00186   int openCol;
00187   int closeLine;
00188   int closeCol;
00189   // note: open/close distinction does not seem needed
00190   // anymore. i keep it to make a potential way back
00191   // easier. overhead is minimal.
00192 };
00193 
00194 struct IndexPair {
00195   int openIndex;
00196   int closeIndex;
00197 };
00198 
00199 
00200 
00201 QVector<KTextEditor::Range> KateRegExpSearch::search(
00202     const QString &pattern,
00203     const KTextEditor::Range & inputRange,
00204     bool backwards)
00205 {
00206   // regex search
00207   KateRegExp regexp(pattern, m_caseSensitivity);
00208 
00209   if (regexp.isEmpty() || !regexp.isValid() || !inputRange.isValid() || (inputRange.start() == inputRange.end()))
00210   {
00211     QVector<KTextEditor::Range> result;
00212     result.append(KTextEditor::Range::invalid());
00213     return result;
00214   }
00215 
00216 
00217   // detect pattern type (single- or mutli-line)
00218   bool isMultiLine;
00219 
00220   // detect '.' and '\s' and fix them
00221   const bool dotMatchesNewline = false; // TODO
00222   const int replacements = regexp.repairPattern(isMultiLine);
00223   if (dotMatchesNewline && (replacements > 0))
00224   {
00225     isMultiLine = true;
00226   }
00227 
00228   const int firstLineIndex = inputRange.start().line();
00229   const int minColStart = inputRange.start().column();
00230 //  const int maxColEnd = inputRange.end().column();
00231   if (isMultiLine)
00232   {
00233     // multi-line regex search (both forward and backward mode)
00234     QString wholeDocument;
00235     const int inputLineCount = inputRange.end().line() - inputRange.start().line() + 1;
00236     FAST_DEBUG("multi line search (lines " << firstLineIndex << ".." << firstLineIndex + inputLineCount - 1 << ")");
00237 
00238     // nothing to do...
00239     if (firstLineIndex >= m_document->lines())
00240     {
00241       QVector<KTextEditor::Range> result;
00242       result.append(KTextEditor::Range::invalid());
00243       return result;
00244     }
00245 
00246     QVector<int> lineLens (inputLineCount);
00247 
00248     // first line
00249     if (firstLineIndex < 0 || m_document->lines() <= firstLineIndex)
00250     {
00251       QVector<KTextEditor::Range> result;
00252       result.append(KTextEditor::Range::invalid());
00253       return result;
00254     }
00255 
00256     const QString firstLine = m_document->line(firstLineIndex);
00257 
00258     const int firstLineLen = firstLine.length() - minColStart;
00259     wholeDocument.append(firstLine.right(firstLineLen));
00260     lineLens[0] = firstLineLen;
00261     FAST_DEBUG("  line" << 0 << "has length" << lineLens[0]);
00262 
00263     // second line and after
00264     const QString sep("\n");
00265     for (int i = 1; i < inputLineCount; i++)
00266     {
00267       const int lineNum = firstLineIndex + i;
00268       if (lineNum < 0 || m_document->lines() <= lineNum)
00269       {
00270         QVector<KTextEditor::Range> result;
00271         result.append(KTextEditor::Range::invalid());
00272         return result;
00273       }
00274       const QString text = m_document->line(lineNum);
00275 
00276       lineLens[i] = text.length();
00277       wholeDocument.append(sep);
00278       wholeDocument.append(text);
00279       FAST_DEBUG("  line" << i << "has length" << lineLens[i]);
00280     }
00281 
00282     const int pos = backwards
00283         ? regexp.lastIndexIn(wholeDocument, 0, wholeDocument.length())
00284         : regexp.indexIn(wholeDocument, 0, wholeDocument.length());
00285     if (pos == -1)
00286     {
00287       // no match
00288       FAST_DEBUG("not found");
00289       {
00290         QVector<KTextEditor::Range> result;
00291         result.append(KTextEditor::Range::invalid());
00292         return result;
00293       }
00294     }
00295 
00296 #ifdef FAST_DEBUG_ENABLE
00297     const int matchLen = regexp.matchedLength();
00298     FAST_DEBUG("found at relative pos " << pos << ", length " << matchLen);
00299 #endif
00300 
00301     // save opening and closing indices and build a map.
00302     // the correct values will be written into it later.
00303     QMap<int, TwoViewCursor *> indicesToCursors;
00304     const int numCaptures = regexp.numCaptures();
00305     QVector<IndexPair> indexPairs(1 + numCaptures);
00306     for (int z = 0; z <= numCaptures; z++)
00307     {
00308       const int openIndex = regexp.pos(z);
00309       IndexPair & pair = indexPairs[z];
00310       if (openIndex == -1)
00311       {
00312         // empty capture gives invalid
00313         pair.openIndex = -1;
00314         pair.closeIndex = -1;
00315         FAST_DEBUG("capture []");
00316       }
00317       else
00318       {
00319         const int closeIndex = openIndex + regexp.cap(z).length();
00320         pair.openIndex = openIndex;
00321         pair.closeIndex = closeIndex;
00322         FAST_DEBUG("capture [" << pair.openIndex << ".." << pair.closeIndex << "]");
00323 
00324         // each key no more than once
00325         if (!indicesToCursors.contains(openIndex))
00326         {
00327           TwoViewCursor * twoViewCursor = new TwoViewCursor;
00328           twoViewCursor->index = openIndex;
00329           indicesToCursors.insert(openIndex, twoViewCursor);
00330           FAST_DEBUG("  border index added: " << openIndex);
00331         }
00332         if (!indicesToCursors.contains(closeIndex))
00333         {
00334           TwoViewCursor * twoViewCursor = new TwoViewCursor;
00335           twoViewCursor->index = closeIndex;
00336           indicesToCursors.insert(closeIndex, twoViewCursor);
00337           FAST_DEBUG("  border index added: " << closeIndex);
00338         }
00339       }
00340     }
00341 
00342     // find out where they belong
00343     int curRelLine = 0;
00344     int curRelCol = 0;
00345     int curRelIndex = 0;
00346     QMap<int, TwoViewCursor *>::const_iterator iter = indicesToCursors.constBegin();
00347     while (iter != indicesToCursors.constEnd())
00348     {
00349       // forward to index, save line/col
00350       const int index = (*iter)->index;
00351       FAST_DEBUG("resolving position" << index);
00352       TwoViewCursor & twoViewCursor = *(*iter);
00353       while (curRelIndex <= index)
00354       {
00355         FAST_DEBUG("walk pos (" << curRelLine << "," << curRelCol << ") = "
00356             << curRelIndex << "relative, steps more to go" << index - curRelIndex);
00357         const int curRelLineLen = lineLens[curRelLine];
00358         const int curLineRemainder = curRelLineLen - curRelCol;
00359         const int lineFeedIndex = curRelIndex + curLineRemainder;
00360         if (index <= lineFeedIndex) {
00361             if (index == lineFeedIndex) {
00362                 // on this line _on_ line feed
00363                 FAST_DEBUG("  on line feed");
00364                 const int absLine = curRelLine + firstLineIndex;
00365                 twoViewCursor.openLine
00366                     = twoViewCursor.closeLine
00367                     = absLine;
00368                 twoViewCursor.openCol
00369                     = twoViewCursor.closeCol
00370                     = ((curRelLine == 0) ? minColStart : 0) + curRelLineLen;
00371 
00372                 // advance to next line
00373                 const int advance = (index - curRelIndex) + 1;
00374                 curRelLine++;
00375                 curRelCol = 0;
00376                 curRelIndex += advance;
00377             } else { // index < lineFeedIndex
00378                 // on this line _before_ line feed
00379                 FAST_DEBUG("  before line feed");
00380                 const int diff = (index - curRelIndex);
00381                 const int absLine = curRelLine + firstLineIndex;
00382                 const int absCol = ((curRelLine == 0) ? minColStart : 0) + curRelCol + diff;
00383                 twoViewCursor.openLine
00384                     = twoViewCursor.closeLine
00385                     = absLine;
00386                 twoViewCursor.openCol
00387                     = twoViewCursor.closeCol
00388                     = absCol;
00389 
00390                 // advance on same line
00391                 const int advance = diff + 1;
00392                 curRelCol += advance;
00393                 curRelIndex += advance;
00394             }
00395             FAST_DEBUG("open(" << twoViewCursor.openLine << "," << twoViewCursor.openCol
00396                 << ")  close(" << twoViewCursor.closeLine << "," << twoViewCursor.closeCol << ")");
00397         }
00398         else // if (index > lineFeedIndex)
00399         {
00400           // not on this line
00401           // advance to next line
00402           FAST_DEBUG("  not on this line");
00403           const int advance = curLineRemainder + 1;
00404           curRelLine++;
00405           curRelCol = 0;
00406           curRelIndex += advance;
00407         }
00408       }
00409 
00410       ++iter;
00411     }
00412 
00413     // build result array
00414     QVector<KTextEditor::Range> result(1 + numCaptures);
00415     for (int y = 0; y <= numCaptures; y++)
00416     {
00417       IndexPair & pair = indexPairs[y];
00418       if ((pair.openIndex == -1) || (pair.closeIndex == -1))
00419       {
00420         result[y] = KTextEditor::Range::invalid();
00421       }
00422       else
00423       {
00424         const TwoViewCursor * const openCursors = indicesToCursors[pair.openIndex];
00425         const TwoViewCursor * const closeCursors = indicesToCursors[pair.closeIndex];
00426         const int startLine = openCursors->openLine;
00427         const int startCol = openCursors->openCol;
00428         const int endLine = closeCursors->closeLine;
00429         const int endCol = closeCursors->closeCol;
00430         FAST_DEBUG("range " << y << ": (" << startLine << ", " << startCol << ")..(" << endLine << ", " << endCol << ")");
00431         result[y] = KTextEditor::Range(startLine, startCol, endLine, endCol);
00432       }
00433     }
00434 
00435     // free structs allocated for indicesToCursors
00436     iter = indicesToCursors.constBegin();
00437     while (iter != indicesToCursors.constEnd())
00438     {
00439       TwoViewCursor * const twoViewCursor = *iter;
00440       delete twoViewCursor;
00441       ++iter;
00442     }
00443     return result;
00444   }
00445   else
00446   {
00447     // single-line regex search (both forward of backward mode)
00448     const int minLeft  = inputRange.start().column();
00449     const uint maxRight = inputRange.end().column(); // first not included
00450     const int forMin   = inputRange.start().line();
00451     const int forMax   = inputRange.end().line();
00452     const int forInit  = backwards ? forMax : forMin;
00453     const int forInc   = backwards ? -1 : +1;
00454     FAST_DEBUG("single line " << (backwards ? forMax : forMin) << ".."
00455       << (backwards ? forMin : forMax));
00456     for (int j = forInit; (forMin <= j) && (j <= forMax); j += forInc)
00457     {
00458       if (j < 0 || m_document->lines() <= j)
00459       {
00460         FAST_DEBUG("searchText | line " << j << ": no");
00461         QVector<KTextEditor::Range> result;
00462         result.append(KTextEditor::Range::invalid());
00463         return result;
00464       }
00465       const QString textLine = m_document->line(j);
00466 
00467         // Find (and don't match ^ in between...)
00468         const int first = (j == forMin) ? minLeft : 0;
00469         const int last = (j == forMax) ? maxRight : textLine.length();
00470         const int foundAt = (backwards ? regexp.lastIndexIn(textLine, first, last)
00471                                        : regexp.indexIn(textLine, first, last));
00472         const bool found = (foundAt != -1);
00473 
00474       /*
00475       TODO do we still need this?
00476 
00477           // A special case which can only occur when searching with a regular expression consisting
00478           // only of a lookahead (e.g. ^(?=\{) for a function beginning without selecting '{').
00479           if (myMatchLen == 0 && line == startPosition.line() && foundAt == (uint) col)
00480           {
00481             if (col < lineLength(line))
00482               col++;
00483             else {
00484               line++;
00485               col = 0;
00486             }
00487             continue;
00488           }
00489       */
00490 
00491       if (found)
00492       {
00493         FAST_DEBUG("line " << j << ": yes");
00494 
00495         // build result array
00496         const int numCaptures = regexp.numCaptures();
00497         QVector<KTextEditor::Range> result(1 + numCaptures);
00498         result[0] = KTextEditor::Range(j, foundAt, j, foundAt + regexp.matchedLength());
00499         FAST_DEBUG("result range " << 0 << ": (" << j << ", " << foundAt << ")..(" << j << ", " <<
00500                 foundAt + regexp.matchedLength() << ")");
00501         for (int y = 1; y <= numCaptures; y++)
00502         {
00503           const int openIndex = regexp.pos(y);
00504           if (openIndex == -1)
00505           {
00506             result[y] = KTextEditor::Range::invalid();
00507             FAST_DEBUG("capture []");
00508           }
00509           else
00510           {
00511             const int closeIndex = openIndex + regexp.cap(y).length();
00512             FAST_DEBUG("result range " << y << ": (" << j << ", " << openIndex << ")..(" << j << ", " << closeIndex << ")");
00513             result[y] = KTextEditor::Range(j, openIndex, j, closeIndex);
00514           }
00515         }
00516         return result;
00517       }
00518       else
00519       {
00520         FAST_DEBUG("searchText | line " << j << ": no");
00521       }
00522     }
00523   }
00524 
00525   QVector<KTextEditor::Range> result;
00526   result.append(KTextEditor::Range::invalid());
00527   return result;
00528 }
00529 
00530 
00531 /*static*/ QString KateRegExpSearch::escapePlaintext(const QString & text)
00532 {
00533   return buildReplacement(text, QStringList(), 0, false);
00534 }
00535 
00536 
00537 /*static*/ QString KateRegExpSearch::buildReplacement(const QString & text, const QStringList &capturedTexts, int replacementCounter)
00538 {
00539   return buildReplacement(text, capturedTexts, replacementCounter, true);
00540 }
00541 
00542 
00543 /*static*/ QString KateRegExpSearch::buildReplacement(const QString & text, const QStringList &capturedTexts, int replacementCounter, bool replacementGoodies) {
00544   // get input
00545   const int inputLen = text.length();
00546   int input = 0; // walker index
00547 
00548   // prepare output
00549   ReplacementStream out(capturedTexts);
00550 
00551   while (input < inputLen)
00552   {
00553     switch (text[input].unicode())
00554     {
00555     case L'\n':
00556       out << text[input];
00557       input++;
00558       break;
00559 
00560     case L'\\':
00561       if (input + 1 >= inputLen)
00562       {
00563         // copy backslash
00564         out << text[input];
00565         input++;
00566         break;
00567       }
00568 
00569       switch (text[input + 1].unicode())
00570       {
00571       case L'0': // "\0000".."\0377"
00572         if (input + 4 >= inputLen)
00573         {
00574           out << ReplacementStream::cap(0);
00575           input += 2;
00576         }
00577         else
00578         {
00579           bool stripAndSkip = false;
00580           const ushort text_2 = text[input + 2].unicode();
00581           if ((text_2 >= L'0') && (text_2 <= L'3'))
00582           {
00583             const ushort text_3 = text[input + 3].unicode();
00584             if ((text_3 >= L'0') && (text_3 <= L'7'))
00585             {
00586               const ushort text_4 = text[input + 4].unicode();
00587               if ((text_4 >= L'0') && (text_4 <= L'7'))
00588               {
00589                 int digits[3];
00590                 for (int i = 0; i < 3; i++)
00591                 {
00592                   digits[i] = 7 - (L'7' - text[input + 2 + i].unicode());
00593                 }
00594                 const int ch = 64 * digits[0] + 8 * digits[1] + digits[2];
00595                 out << QChar(ch);
00596                 input += 5;
00597               }
00598               else
00599               {
00600                 stripAndSkip = true;
00601               }
00602             }
00603             else
00604             {
00605               stripAndSkip = true;
00606             }
00607           }
00608           else
00609           {
00610             stripAndSkip = true;
00611           }
00612 
00613           if (stripAndSkip)
00614           {
00615             out << ReplacementStream::cap(0);
00616             input += 2;
00617           }
00618         }
00619         break;
00620 
00621       case L'1':
00622       case L'2':
00623       case L'3':
00624       case L'4':
00625       case L'5':
00626       case L'6':
00627       case L'7':
00628       case L'8':
00629       case L'9':
00630         out << ReplacementStream::cap(9 - (L'9' - text[input + 1].unicode()));
00631         input += 2;
00632         break;
00633 
00634       case L'E': // FALLTHROUGH
00635       case L'L': // FALLTHROUGH
00636       case L'l': // FALLTHROUGH
00637       case L'U': // FALLTHROUGH
00638       case L'u':
00639         if (!replacementGoodies) {
00640           // strip backslash ("\?" -> "?")
00641           out << text[input + 1];
00642         } else {
00643           // handle case switcher
00644           switch (text[input + 1].unicode()) {
00645           case L'L':
00646             out << ReplacementStream::lowerCase;
00647             break;
00648 
00649           case L'l':
00650             out << ReplacementStream::lowerCaseFirst;
00651             break;
00652 
00653           case L'U':
00654             out << ReplacementStream::upperCase;
00655             break;
00656 
00657           case L'u':
00658             out << ReplacementStream::upperCaseFirst;
00659             break;
00660 
00661           case L'E': // FALLTHROUGH
00662           default:
00663             out << ReplacementStream::keepCase;
00664 
00665           }
00666         }
00667         input += 2;
00668         break;
00669 
00670       case L'#':
00671         if (!replacementGoodies) {
00672           // strip backslash ("\?" -> "?")
00673           out << text[input + 1];
00674           input += 2;
00675         } else {
00676           // handle replacement counter
00677           // eat and count all following hash marks
00678           // each hash stands for a leading zero: \### will produces 001, 002, ...
00679           int minWidth = 1;
00680           while ((input + minWidth + 1 < inputLen) && (text[input + minWidth + 1].unicode() == L'#')) {
00681             minWidth++;
00682           }
00683           out << ReplacementStream::counter(replacementCounter, minWidth);
00684           input += 1 + minWidth;
00685         }
00686         break;
00687 
00688       case L'a':
00689         out << QChar(0x07);
00690         input += 2;
00691         break;
00692 
00693       case L'f':
00694         out << QChar(0x0c);
00695         input += 2;
00696         break;
00697 
00698       case L'n':
00699         out << QChar(0x0a);
00700         input += 2;
00701         break;
00702 
00703       case L'r':
00704         out << QChar(0x0d);
00705         input += 2;
00706         break;
00707 
00708       case L't':
00709         out << QChar(0x09);
00710         input += 2;
00711         break;
00712 
00713       case L'v':
00714         out << QChar(0x0b);
00715         input += 2;
00716         break;
00717 
00718       case L'x': // "\x0000".."\xffff"
00719         if (input + 5 >= inputLen)
00720         {
00721           // strip backslash ("\x" -> "x")
00722           out << text[input + 1];
00723           input += 2;
00724         }
00725         else
00726         {
00727           bool stripAndSkip = false;
00728           const ushort text_2 = text[input + 2].unicode();
00729           if (((text_2 >= L'0') && (text_2 <= L'9'))
00730               || ((text_2 >= L'a') && (text_2 <= L'f'))
00731               || ((text_2 >= L'A') && (text_2 <= L'F')))
00732           {
00733             const ushort text_3 = text[input + 3].unicode();
00734             if (((text_3 >= L'0') && (text_3 <= L'9'))
00735                 || ((text_3 >= L'a') && (text_3 <= L'f'))
00736                 || ((text_3 >= L'A') && (text_3 <= L'F')))
00737             {
00738               const ushort text_4 = text[input + 4].unicode();
00739               if (((text_4 >= L'0') && (text_4 <= L'9'))
00740                   || ((text_4 >= L'a') && (text_4 <= L'f'))
00741                   || ((text_4 >= L'A') && (text_4 <= L'F')))
00742               {
00743                 const ushort text_5 = text[input + 5].unicode();
00744                 if (((text_5 >= L'0') && (text_5 <= L'9'))
00745                     || ((text_5 >= L'a') && (text_5 <= L'f'))
00746                     || ((text_5 >= L'A') && (text_5 <= L'F')))
00747                 {
00748                   int digits[4];
00749                   for (int i = 0; i < 4; i++)
00750                   {
00751                     const ushort cur = text[input + 2 + i].unicode();
00752                     if ((cur >= L'0') && (cur <= L'9'))
00753                     {
00754                       digits[i] = 9 - (L'9' - cur);
00755                     }
00756                     else if ((cur >= L'a') && (cur <= L'f'))
00757                     {
00758                       digits[i] = 15 - (L'f' - cur);
00759                     }
00760                     else // if ((cur >= L'A') && (cur <= L'F')))
00761                     {
00762                       digits[i] = 15 - (L'F' - cur);
00763                     }
00764                   }
00765 
00766                   const int ch = 4096 * digits[0] + 256 * digits[1] + 16 * digits[2] + digits[3];
00767                   out << QChar(ch);
00768                   input += 6;
00769                 }
00770                 else
00771                 {
00772                   stripAndSkip = true;
00773                 }
00774               }
00775               else
00776               {
00777                 stripAndSkip = true;
00778               }
00779             }
00780             else
00781             {
00782               stripAndSkip = true;
00783             }
00784           }
00785 
00786           if (stripAndSkip)
00787           {
00788             // strip backslash ("\x" -> "x")
00789             out << text[input + 1];
00790             input += 2;
00791           }
00792         }
00793         break;
00794 
00795       default:
00796         // strip backslash ("\?" -> "?")
00797         out << text[input + 1];
00798         input += 2;
00799 
00800       }
00801       break;
00802 
00803     default:
00804       out << text[input];
00805       input++;
00806 
00807     }
00808   }
00809 
00810   return out.str();
00811 }
00812 
00813 
00814 // Kill our helpers again
00815 #ifdef FAST_DEBUG_ENABLE
00816 # undef FAST_DEBUG_ENABLE
00817 #endif
00818 #undef FAST_DEBUG
00819 
00820 // kate: space-indent on; indent-width 2; replace-tabs on;

Kate

Skip menu "Kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal