kstringhandler.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 1999 Ian Zepp (icszepp@islc.net) 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "kstringhandler.h" 00021 #include "tdeglobal.h" 00022 00023 static void parsePythonRange( const TQCString &range, uint &start, uint &end ) 00024 { 00025 const int colon = range.find( ':' ); 00026 if ( colon == -1 ) { 00027 start = range.toUInt(); 00028 end = start; 00029 } else if ( colon == int( range.length() - 1 ) ) { 00030 start = range.left( colon ).toUInt(); 00031 } else if ( colon == 0 ) { 00032 end = range.mid( 1 ).toUInt(); 00033 } else { 00034 start = range.left( colon ).toInt(); 00035 end = range.mid( colon + 1 ).toInt(); 00036 } 00037 } 00038 00039 TQString KStringHandler::word( const TQString &text , uint pos ) 00040 { 00041 return text.section( ' ', pos, pos ); 00042 } 00043 00044 TQString KStringHandler::word( const TQString &text , const char *range ) 00045 { 00046 // Format in: START:END 00047 // Note index starts a 0 (zero) 00048 // 00049 // 0: first word to end 00050 // 1:3 second to fourth words 00051 TQStringList list = TQStringList::split( " ", text , true ); 00052 TQString tmp = ""; 00053 TQString r = range; 00054 00055 if ( text.isEmpty() ) 00056 return tmp; 00057 00058 uint pos = 0, cnt = list.count(); 00059 parsePythonRange( range, pos, cnt ); 00060 00061 // 00062 // Extract words 00063 // 00064 int wordsToExtract = cnt-pos+1; 00065 TQStringList::Iterator it = list.at( pos); 00066 00067 while ( (it != list.end()) && (wordsToExtract-- > 0)) 00068 { 00069 tmp += *it; 00070 tmp += " "; 00071 it++; 00072 } 00073 00074 return tmp.stripWhiteSpace(); 00075 } 00076 00077 // 00078 // Insertion and removal routines 00079 // 00080 TQString KStringHandler::insword( const TQString &text , const TQString &word , uint pos ) 00081 { 00082 if ( text.isEmpty() ) 00083 return word; 00084 00085 if ( word.isEmpty() ) 00086 return text; 00087 00088 // Split words and add into list 00089 TQStringList list = TQStringList::split( " ", text, true ); 00090 00091 if ( pos >= list.count() ) 00092 list.append( word ); 00093 else 00094 list.insert( list.at(pos) , word ); 00095 00096 // Rejoin 00097 return list.join( " " ); 00098 } 00099 00100 TQString KStringHandler::setword( const TQString &text , const TQString &word , uint pos ) 00101 { 00102 if ( text.isEmpty() ) 00103 return word; 00104 00105 if ( word.isEmpty() ) 00106 return text; 00107 00108 // Split words and add into list 00109 TQStringList list = TQStringList::split( " ", text, true ); 00110 00111 if ( pos >= list.count() ) 00112 list.append( word ); 00113 else 00114 { 00115 list.insert( list.remove( list.at(pos) ) , word ); 00116 } 00117 00118 // Rejoin 00119 return list.join( " " ); 00120 } 00121 00122 TQString KStringHandler::remrange( const TQString &text , const char *range ) 00123 { 00124 // Format in: START:END 00125 // Note index starts a 0 (zero) 00126 // 00127 // 0: first word to end 00128 // 1:3 second to fourth words 00129 TQStringList list = TQStringList::split( " ", text , true ); 00130 TQString tmp = ""; 00131 TQString r = range; 00132 00133 if ( text.isEmpty() ) 00134 return tmp; 00135 00136 uint pos = 0, cnt = list.count(); 00137 parsePythonRange( range, pos, cnt ); 00138 00139 // 00140 // Remove that range of words 00141 // 00142 int wordsToDelete = cnt-pos+1; 00143 TQStringList::Iterator it = list.at( pos); 00144 00145 while ( (it != list.end()) && (wordsToDelete-- > 0)) 00146 it = list.remove( it ); 00147 00148 return list.join( " " ); 00149 } 00150 00151 TQString KStringHandler::remword( const TQString &text , uint pos ) 00152 { 00153 TQString tmp = ""; 00154 00155 if ( text.isEmpty() ) 00156 return tmp; 00157 00158 // Split words and add into list 00159 TQStringList list = TQStringList::split( " ", text, true ); 00160 00161 if ( pos < list.count() ) 00162 list.remove( list.at( pos ) ); 00163 00164 // Rejoin 00165 return list.join( " " ); 00166 } 00167 00168 TQString KStringHandler::remword( const TQString &text , const TQString &word ) 00169 { 00170 TQString tmp = ""; 00171 00172 if ( text.isEmpty() ) 00173 return tmp; 00174 00175 if ( word.isEmpty() ) 00176 return text; 00177 00178 // Split words and add into list 00179 TQStringList list = TQStringList::split( " ", text, true ); 00180 00181 TQStringList::Iterator it = list.find(word); 00182 00183 if (it != list.end()) 00184 list.remove( it ); 00185 00186 // Rejoin 00187 return list.join( " " ); 00188 } 00189 00190 // 00191 // Capitalization routines 00192 // 00193 TQString KStringHandler::capwords( const TQString &text ) 00194 { 00195 if ( text.isEmpty() ) { 00196 return text; 00197 } 00198 00199 const TQString strippedText = text.stripWhiteSpace(); 00200 const TQStringList words = capwords( TQStringList::split( ' ', strippedText ) ); 00201 00202 TQString result = text; 00203 result.replace( strippedText, words.join( " " ) ); 00204 return result; 00205 } 00206 00207 TQStringList KStringHandler::capwords( const TQStringList &list ) 00208 { 00209 TQStringList tmp = list; 00210 for ( TQStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it ) { 00211 *it = ( *it )[ 0 ].upper() + ( *it ).mid( 1 ); 00212 } 00213 return tmp; 00214 } 00215 00216 // 00217 // Reverse routines 00218 // 00219 TQString KStringHandler::reverse( const TQString &text ) 00220 { 00221 TQString tmp; 00222 00223 if ( text.isEmpty() ) 00224 return tmp; 00225 00226 TQStringList list; 00227 list = TQStringList::split( " ", text, true ); 00228 list = reverse( list ); 00229 00230 return list.join( " " ); 00231 } 00232 00233 TQStringList KStringHandler::reverse( const TQStringList &list ) 00234 { 00235 TQStringList tmp; 00236 00237 if ( list.count() == 0 ) 00238 return tmp; 00239 00240 for ( TQStringList::ConstIterator it= list.begin(); 00241 it != list.end(); 00242 it++) 00243 tmp.prepend( *it ); 00244 00245 return tmp; 00246 } 00247 00248 // 00249 // Left, Right, Center justification 00250 // 00251 TQString KStringHandler::ljust( const TQString &text , uint width ) 00252 { 00253 return text.stripWhiteSpace().leftJustify( width ); 00254 } 00255 00256 TQString KStringHandler::rjust( const TQString &text , uint width ) 00257 { 00258 return text.stripWhiteSpace().rightJustify( width ); 00259 } 00260 00261 TQString KStringHandler::center( const TQString &text , uint width ) 00262 { 00263 const TQString s = text.stripWhiteSpace(); 00264 const unsigned int length = s.length(); 00265 if ( width <= length ) { 00266 return s; 00267 } 00268 00269 TQString result; 00270 result.fill( ' ', ( width - length ) / 2 ); 00271 result += s; 00272 00273 return result.leftJustify( width ); 00274 } 00275 00276 TQString KStringHandler::lsqueeze( const TQString & str, uint maxlen ) 00277 { 00278 if (str.length() > maxlen) { 00279 int part = maxlen-3; 00280 return TQString("..." + str.right(part)); 00281 } 00282 else return str; 00283 } 00284 00285 TQString KStringHandler::csqueeze( const TQString & str, uint maxlen ) 00286 { 00287 if (str.length() > maxlen && maxlen > 3) { 00288 int part = (maxlen-3)/2; 00289 return TQString(str.left(part) + "..." + str.right(part)); 00290 } 00291 else return str; 00292 } 00293 00294 TQString KStringHandler::rsqueeze( const TQString & str, uint maxlen ) 00295 { 00296 if (str.length() > maxlen) { 00297 int part = maxlen-3; 00298 return TQString(str.left(part) + "..."); 00299 } 00300 else return str; 00301 } 00302 00303 TQString KStringHandler::lEmSqueeze(const TQString &name, const TQFontMetrics& fontMetrics, uint maxlen) 00304 { 00305 return lPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); 00306 } 00307 00308 TQString KStringHandler::lPixelSqueeze(const TQString& name, const TQFontMetrics& fontMetrics, uint maxPixels) 00309 { 00310 uint nameWidth = fontMetrics.width(name); 00311 00312 if (maxPixels < nameWidth) 00313 { 00314 TQString tmp = name; 00315 const uint em = fontMetrics.maxWidth(); 00316 maxPixels -= fontMetrics.width("..."); 00317 00318 while (maxPixels < nameWidth && !tmp.isEmpty()) 00319 { 00320 int delta = (nameWidth - maxPixels) / em; 00321 delta = kClamp(delta, 1, delta); // no max 00322 00323 tmp.remove(0, delta); 00324 nameWidth = fontMetrics.width(tmp); 00325 } 00326 00327 return ("..." + tmp); 00328 } 00329 00330 return name; 00331 } 00332 00333 TQString KStringHandler::cEmSqueeze(const TQString& name, const TQFontMetrics& fontMetrics, uint maxlen) 00334 { 00335 return cPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); 00336 } 00337 00338 TQString KStringHandler::cPixelSqueeze(const TQString& s, const TQFontMetrics& fm, uint width) 00339 { 00340 if ( s.isEmpty() || uint( fm.width( s ) ) <= width ) { 00341 return s; 00342 } 00343 00344 const unsigned int length = s.length(); 00345 if ( length == 2 ) { 00346 return s; 00347 } 00348 00349 const int maxWidth = width - fm.width( '.' ) * 3; 00350 if ( maxWidth <= 0 ) { 00351 return "..."; 00352 } 00353 00354 unsigned int leftIdx = 0, rightIdx = length; 00355 unsigned int leftWidth = fm.charWidth( s, leftIdx++ ); 00356 unsigned int rightWidth = fm.charWidth( s, --rightIdx ); 00357 while ( leftWidth + rightWidth < uint( maxWidth ) ) { 00358 while ( leftWidth <= rightWidth && leftWidth + rightWidth < uint( maxWidth ) ) { 00359 leftWidth += fm.charWidth( s, leftIdx++ ); 00360 } 00361 while ( rightWidth <= leftWidth && leftWidth + rightWidth < uint( maxWidth ) ) { 00362 rightWidth += fm.charWidth( s, --rightIdx ); 00363 } 00364 } 00365 00366 if ( leftWidth > rightWidth ) { 00367 --leftIdx; 00368 } else { 00369 ++rightIdx; 00370 } 00371 00372 rightIdx = length - rightIdx; 00373 if ( leftIdx == 0 && rightIdx == 1 || leftIdx == 1 && rightIdx == 0 ) { 00374 return "..."; 00375 } 00376 00377 return s.left( leftIdx ) + "..." + s.right( rightIdx ); 00378 } 00379 00380 TQString KStringHandler::rEmSqueeze(const TQString& name, const TQFontMetrics& fontMetrics, uint maxlen) 00381 { 00382 return rPixelSqueeze(name, fontMetrics, fontMetrics.maxWidth() * maxlen); 00383 } 00384 00385 TQString KStringHandler::rPixelSqueeze(const TQString& name, const TQFontMetrics& fontMetrics, uint maxPixels) 00386 { 00387 uint nameWidth = fontMetrics.width(name); 00388 00389 if (maxPixels < nameWidth) 00390 { 00391 TQString tmp = name; 00392 const uint em = fontMetrics.maxWidth(); 00393 maxPixels -= fontMetrics.width("..."); 00394 00395 while (maxPixels < nameWidth && !tmp.isEmpty()) 00396 { 00397 int length = tmp.length(); 00398 int delta = em ? (nameWidth - maxPixels) / em : length; 00399 delta = kClamp(delta, 1, length) ; 00400 00401 tmp.remove(length - delta, delta); 00402 nameWidth = fontMetrics.width(tmp); 00403 } 00404 00405 return (tmp + "..."); 00406 } 00407 00408 return name; 00409 } 00410 00412 00413 bool KStringHandler::matchFileName( const TQString& filename, const TQString& pattern ) 00414 { 00415 int len = filename.length(); 00416 int pattern_len = pattern.length(); 00417 00418 if (!pattern_len) 00419 return false; 00420 00421 // Patterns like "Makefile*" 00422 if ( pattern[ pattern_len - 1 ] == (QChar)'*' && len + 1 >= pattern_len ) { 00423 if ( pattern[ 0 ] == (QChar)'*' ) 00424 { 00425 return filename.find(pattern.mid(1, pattern_len - 2)) != -1; 00426 } 00427 00428 const TQChar *c1 = pattern.unicode(); 00429 const TQChar *c2 = filename.unicode(); 00430 int cnt = 1; 00431 while ( cnt < pattern_len && *c1++ == *c2++ ) 00432 ++cnt; 00433 return cnt == pattern_len; 00434 } 00435 00436 // Patterns like "*~", "*.extension" 00437 if ( pattern[ 0 ] == (QChar)'*' && len + 1 >= pattern_len ) 00438 { 00439 const TQChar *c1 = pattern.unicode() + pattern_len - 1; 00440 const TQChar *c2 = filename.unicode() + len - 1; 00441 int cnt = 1; 00442 while ( cnt < pattern_len && *c1-- == *c2-- ) 00443 ++cnt; 00444 return cnt == pattern_len; 00445 } 00446 00447 // Patterns like "Makefile" 00448 return ( filename == pattern ); 00449 } 00450 00451 TQStringList 00452 KStringHandler::perlSplit(const TQString & sep, const TQString & s, uint max) 00453 { 00454 bool ignoreMax = 0 == max; 00455 00456 TQStringList l; 00457 00458 int searchStart = 0; 00459 00460 int tokenStart = s.find(sep, searchStart); 00461 00462 while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) 00463 { 00464 if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) 00465 l << s.mid(searchStart, tokenStart - searchStart); 00466 00467 searchStart = tokenStart + sep.length(); 00468 tokenStart = s.find(sep, searchStart); 00469 } 00470 00471 if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) 00472 l << s.mid(searchStart, s.length() - searchStart); 00473 00474 return l; 00475 } 00476 00477 TQStringList 00478 KStringHandler::perlSplit(const TQChar & sep, const TQString & s, uint max) 00479 { 00480 bool ignoreMax = 0 == max; 00481 00482 TQStringList l; 00483 00484 int searchStart = 0; 00485 00486 int tokenStart = s.find(sep, searchStart); 00487 00488 while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) 00489 { 00490 if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) 00491 l << s.mid(searchStart, tokenStart - searchStart); 00492 00493 searchStart = tokenStart + 1; 00494 tokenStart = s.find(sep, searchStart); 00495 } 00496 00497 if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) 00498 l << s.mid(searchStart, s.length() - searchStart); 00499 00500 return l; 00501 } 00502 00503 TQStringList 00504 KStringHandler::perlSplit(const TQRegExp & sep, const TQString & s, uint max) 00505 { 00506 bool ignoreMax = 0 == max; 00507 00508 TQStringList l; 00509 00510 int searchStart = 0; 00511 int tokenStart = sep.search(s, searchStart); 00512 int len = sep.matchedLength(); 00513 00514 while (-1 != tokenStart && (ignoreMax || l.count() < max - 1)) 00515 { 00516 if (!s.mid(searchStart, tokenStart - searchStart).isEmpty()) 00517 l << s.mid(searchStart, tokenStart - searchStart); 00518 00519 searchStart = tokenStart + len; 00520 tokenStart = sep.search(s, searchStart); 00521 len = sep.matchedLength(); 00522 } 00523 00524 if (!s.mid(searchStart, s.length() - searchStart).isEmpty()) 00525 l << s.mid(searchStart, s.length() - searchStart); 00526 00527 return l; 00528 } 00529 00530 TQString 00531 KStringHandler::tagURLs( const TQString& text ) 00532 { 00533 /*static*/ TQRegExp urlEx("(www\\.(?!\\.)|(fish|(f|ht)tp(|s))://)[\\d\\w\\./,:_~\\?=&;#@\\-\\+\\%\\$]+[\\d\\w/]"); 00534 00535 TQString richText( text ); 00536 int urlPos = 0, urlLen; 00537 while ((urlPos = urlEx.search(richText, urlPos)) >= 0) 00538 { 00539 urlLen = urlEx.matchedLength(); 00540 TQString href = richText.mid( urlPos, urlLen ); 00541 // Qt doesn't support (?<=pattern) so we do it here 00542 if((urlPos > 0) && richText[urlPos-1].isLetterOrNumber()){ 00543 urlPos++; 00544 continue; 00545 } 00546 // Don't use TQString::arg since %01, %20, etc could be in the string 00547 TQString anchor = "<a href=\"" + href + "\">" + href + "</a>"; 00548 richText.replace( urlPos, urlLen, anchor ); 00549 00550 00551 urlPos += anchor.length(); 00552 } 00553 return richText; 00554 } 00555 00556 TQString KStringHandler::obscure( const TQString &str ) 00557 { 00558 TQString result; 00559 const TQChar *unicode = str.unicode(); 00560 for ( uint i = 0; i < str.length(); ++i ) 00561 result += ( unicode[ i ].unicode() < 0x21 ) ? unicode[ i ] : 00562 TQChar( 0x1001F - unicode[ i ].unicode() ); 00563 00564 return result; 00565 } 00566 00567 bool KStringHandler::isUtf8(const char *buf) 00568 { 00569 int i, n; 00570 unsigned char c; 00571 bool gotone = false; 00572 00573 if (!buf) 00574 return true; // whatever, just don't crash 00575 00576 #define F 0 /* character never appears in text */ 00577 #define T 1 /* character appears in plain ASCII text */ 00578 #define I 2 /* character appears in ISO-8859 text */ 00579 #define X 3 /* character appears in non-ISO extended ASCII (Mac, IBM PC) */ 00580 00581 static const unsigned char text_chars[256] = { 00582 /* BEL BS HT LF FF CR */ 00583 F, F, F, F, F, F, F, T, T, T, T, F, T, T, F, F, /* 0x0X */ 00584 /* ESC */ 00585 F, F, F, F, F, F, F, F, F, F, F, T, F, F, F, F, /* 0x1X */ 00586 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x2X */ 00587 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x3X */ 00588 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x4X */ 00589 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x5X */ 00590 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, /* 0x6X */ 00591 T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, F, /* 0x7X */ 00592 /* NEL */ 00593 X, X, X, X, X, T, X, X, X, X, X, X, X, X, X, X, /* 0x8X */ 00594 X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, X, /* 0x9X */ 00595 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xaX */ 00596 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xbX */ 00597 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xcX */ 00598 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xdX */ 00599 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, /* 0xeX */ 00600 I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I /* 0xfX */ 00601 }; 00602 00603 /* *ulen = 0; */ 00604 for (i = 0; (c = buf[i]); i++) { 00605 if ((c & 0x80) == 0) { /* 0xxxxxxx is plain ASCII */ 00606 /* 00607 * Even if the whole file is valid UTF-8 sequences, 00608 * still reject it if it uses weird control characters. 00609 */ 00610 00611 if (text_chars[c] != T) 00612 return false; 00613 00614 } else if ((c & 0x40) == 0) { /* 10xxxxxx never 1st byte */ 00615 return false; 00616 } else { /* 11xxxxxx begins UTF-8 */ 00617 int following; 00618 00619 if ((c & 0x20) == 0) { /* 110xxxxx */ 00620 following = 1; 00621 } else if ((c & 0x10) == 0) { /* 1110xxxx */ 00622 following = 2; 00623 } else if ((c & 0x08) == 0) { /* 11110xxx */ 00624 following = 3; 00625 } else if ((c & 0x04) == 0) { /* 111110xx */ 00626 following = 4; 00627 } else if ((c & 0x02) == 0) { /* 1111110x */ 00628 following = 5; 00629 } else 00630 return false; 00631 00632 for (n = 0; n < following; n++) { 00633 i++; 00634 if (!(c = buf[i])) 00635 goto done; 00636 00637 if ((c & 0x80) == 0 || (c & 0x40)) 00638 return false; 00639 } 00640 gotone = true; 00641 } 00642 } 00643 done: 00644 return gotone; /* don't claim it's UTF-8 if it's all 7-bit */ 00645 } 00646 00647 #undef F 00648 #undef T 00649 #undef I 00650 #undef X 00651 00652 TQString KStringHandler::from8Bit( const char *str ) 00653 { 00654 if (!str) 00655 return TQString::null; 00656 if (!*str) { 00657 static const TQString &emptyString = TDEGlobal::staticQString(""); 00658 return emptyString; 00659 } 00660 return KStringHandler::isUtf8( str ) ? 00661 TQString::fromUtf8( str ) : 00662 TQString::fromLocal8Bit( str ); 00663 }