1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 // MARKER(update_precomp.py): autogen include statement, do not remove 23 #include "precompiled_basic.hxx" 24 25 #include "sbcomp.hxx" 26 #include <stdio.h> 27 #include <string.h> 28 #include <ctype.h> 29 #if defined UNX 30 #include <stdlib.h> 31 #else 32 #include <math.h> // atof() 33 #endif 34 #include <rtl/math.hxx> 35 #include <vcl/svapp.hxx> 36 #include <unotools/charclass.hxx> 37 38 #include <runtime.hxx> 39 40 SbiScanner::SbiScanner( const ::rtl::OUString& rBuf, StarBASIC* p ) : aBuf( rBuf ) 41 { 42 pBasic = p; 43 pLine = NULL; 44 nVal = 0; 45 eScanType = SbxVARIANT; 46 nErrors = 0; 47 nBufPos = 0; 48 nCurCol1 = 0; 49 nSavedCol1 = 0; 50 nColLock = 0; 51 nLine = 0; 52 nCol1 = 0; 53 nCol2 = 0; 54 nCol = 0; 55 bError = 56 bAbort = 57 bSpaces = 58 bNumber = 59 bSymbol = 60 bUsedForHilite = 61 bCompatible = 62 bVBASupportOn = 63 bPrevLineExtentsComment = sal_False; 64 bHash = 65 bErrors = sal_True; 66 } 67 68 SbiScanner::~SbiScanner() 69 {} 70 71 void SbiScanner::LockColumn() 72 { 73 if( !nColLock++ ) 74 nSavedCol1 = nCol1; 75 } 76 77 void SbiScanner::UnlockColumn() 78 { 79 if( nColLock ) 80 nColLock--; 81 } 82 83 void SbiScanner::GenError( SbError code ) 84 { 85 if( GetSbData()->bBlockCompilerError ) 86 { 87 bAbort = sal_True; 88 return; 89 } 90 if( !bError && bErrors ) 91 { 92 sal_Bool bRes = sal_True; 93 // Nur einen Fehler pro Statement reporten 94 bError = sal_True; 95 if( pBasic ) 96 { 97 // Falls EXPECTED oder UNEXPECTED kommen sollte, bezieht es sich 98 // immer auf das letzte Token, also die Col1 übernehmen 99 sal_uInt16 nc = nColLock ? nSavedCol1 : nCol1; 100 switch( code ) 101 { 102 case SbERR_EXPECTED: 103 case SbERR_UNEXPECTED: 104 case SbERR_SYMBOL_EXPECTED: 105 case SbERR_LABEL_EXPECTED: 106 nc = nCol1; 107 if( nc > nCol2 ) nCol2 = nc; 108 break; 109 } 110 bRes = pBasic->CError( code, aError, nLine, nc, nCol2 ); 111 } 112 bAbort |= !bRes | 113 ( code == SbERR_NO_MEMORY || code == SbERR_PROG_TOO_LARGE ); 114 } 115 if( bErrors ) 116 nErrors++; 117 } 118 119 // Falls sofort ein Doppelpunkt folgt, wird sal_True zurückgeliefert. 120 // Wird von SbiTokenizer::MayBeLabel() verwendet, um einen Label zu erkennen 121 122 sal_Bool SbiScanner::DoesColonFollow() 123 { 124 if( pLine && *pLine == ':' ) 125 { 126 pLine++; nCol++; return sal_True; 127 } 128 else return sal_False; 129 } 130 131 // Testen auf ein legales Suffix 132 133 static SbxDataType GetSuffixType( sal_Unicode c ) 134 { 135 static String aSuffixesStr = String::CreateFromAscii( "%&!#@ $" ); 136 if( c ) 137 { 138 sal_uInt32 n = aSuffixesStr.Search( c ); 139 if( STRING_NOTFOUND != n && c != ' ' ) 140 return SbxDataType( (sal_uInt16) n + SbxINTEGER ); 141 } 142 return SbxVARIANT; 143 } 144 145 // Einlesen des nächsten Symbols in die Variablen aSym, nVal und eType 146 // Returnwert ist sal_False bei EOF oder Fehlern 147 #define BUF_SIZE 80 148 149 namespace { 150 151 /** Returns true, if the passed character is a white space character. */ 152 inline bool lclIsWhitespace( sal_Unicode cChar ) 153 { 154 return (cChar == ' ') || (cChar == '\t') || (cChar == '\f'); 155 } 156 157 } // namespace 158 159 sal_Bool SbiScanner::NextSym() 160 { 161 // Für den EOLN-Fall merken 162 sal_uInt16 nOldLine = nLine; 163 sal_uInt16 nOldCol1 = nCol1; 164 sal_uInt16 nOldCol2 = nCol2; 165 sal_Unicode buf[ BUF_SIZE ], *p = buf; 166 bHash = sal_False; 167 168 eScanType = SbxVARIANT; 169 aSym.Erase(); 170 bSymbol = 171 bNumber = bSpaces = sal_False; 172 173 // Zeile einlesen? 174 if( !pLine ) 175 { 176 sal_Int32 n = nBufPos; 177 sal_Int32 nLen = aBuf.getLength(); 178 if( nBufPos >= nLen ) 179 return sal_False; 180 const sal_Unicode* p2 = aBuf.getStr(); 181 p2 += n; 182 while( ( n < nLen ) && ( *p2 != '\n' ) && ( *p2 != '\r' ) ) 183 p2++, n++; 184 // #163944# ignore trailing whitespace 185 sal_Int32 nCopyEndPos = n; 186 while( (nBufPos < nCopyEndPos) && lclIsWhitespace( aBuf[ nCopyEndPos - 1 ] ) ) 187 --nCopyEndPos; 188 aLine = aBuf.copy( nBufPos, nCopyEndPos - nBufPos ); 189 if( n < nLen ) 190 { 191 if( *p2 == '\r' && *( p2+1 ) == '\n' ) 192 n += 2; 193 else 194 n++; 195 } 196 nBufPos = n; 197 pLine = aLine.getStr(); 198 nOldLine = ++nLine; 199 nCol = nCol1 = nCol2 = nOldCol1 = nOldCol2 = 0; 200 nColLock = 0; 201 } 202 203 // Leerstellen weg: 204 while( lclIsWhitespace( *pLine ) ) 205 pLine++, nCol++, bSpaces = sal_True; 206 207 nCol1 = nCol; 208 209 // nur Leerzeile? 210 if( !*pLine ) 211 goto eoln; 212 213 if( bPrevLineExtentsComment ) 214 goto PrevLineCommentLbl; 215 216 if( *pLine == '#' ) 217 { 218 pLine++; 219 nCol++; 220 bHash = sal_True; 221 } 222 223 // Symbol? Dann Zeichen kopieren. 224 if( BasicSimpleCharClass::isAlpha( *pLine, bCompatible ) || *pLine == '_' ) 225 { 226 // Wenn nach '_' nichts kommt, ist es ein Zeilenabschluss! 227 if( *pLine == '_' && !*(pLine+1) ) 228 { pLine++; 229 goto eoln; } 230 bSymbol = sal_True; 231 short n = nCol; 232 for ( ; (BasicSimpleCharClass::isAlphaNumeric( *pLine, bCompatible ) || ( *pLine == '_' ) ); pLine++ ) 233 nCol++; 234 aSym = aLine.copy( n, nCol - n ); 235 236 // Special handling for "go to" 237 if( bCompatible && *pLine && aSym.EqualsIgnoreCaseAscii( "go" ) ) 238 { 239 const sal_Unicode* pTestLine = pLine; 240 short nTestCol = nCol; 241 while( lclIsWhitespace( *pTestLine ) ) 242 { 243 pTestLine++; 244 nTestCol++; 245 } 246 247 if( *pTestLine && *(pTestLine + 1) ) 248 { 249 String aTestSym = aLine.copy( nTestCol, 2 ); 250 if( aTestSym.EqualsIgnoreCaseAscii( "to" ) ) 251 { 252 aSym = String::CreateFromAscii( "goto" ); 253 pLine = pTestLine + 2; 254 nCol = nTestCol + 2; 255 } 256 } 257 } 258 259 // Abschließendes '_' durch Space ersetzen, wenn Zeilenende folgt 260 // (sonst falsche Zeilenfortsetzung) 261 if( !bUsedForHilite && !*pLine && *(pLine-1) == '_' ) 262 { 263 aSym.GetBufferAccess(); // #109693 force copy if necessary 264 *((sal_Unicode*)(pLine-1)) = ' '; // cast wegen const 265 } 266 // Typkennung? 267 // Das Ausrufezeichen bitte nicht testen, wenn 268 // danach noch ein Symbol anschließt 269 else if( *pLine != '!' || !BasicSimpleCharClass::isAlpha( pLine[ 1 ], bCompatible ) ) 270 { 271 SbxDataType t = GetSuffixType( *pLine ); 272 if( t != SbxVARIANT ) 273 { 274 eScanType = t; 275 pLine++; 276 nCol++; 277 } 278 } 279 } 280 281 // Zahl? Dann einlesen und konvertieren. 282 else if( BasicSimpleCharClass::isDigit( *pLine & 0xFF ) 283 || ( *pLine == '.' && BasicSimpleCharClass::isDigit( *(pLine+1) & 0xFF ) ) ) 284 { 285 short exp = 0; 286 short comma = 0; 287 short ndig = 0; 288 short ncdig = 0; 289 eScanType = SbxDOUBLE; 290 sal_Bool bBufOverflow = sal_False; 291 while( strchr( "0123456789.DEde", *pLine ) && *pLine ) 292 { 293 // AB 4.1.1996: Buffer voll? -> leer weiter scannen 294 if( (p-buf) == (BUF_SIZE-1) ) 295 { 296 bBufOverflow = sal_True; 297 pLine++, nCol++; 298 continue; 299 } 300 // Komma oder Exponent? 301 if( *pLine == '.' ) 302 { 303 if( ++comma > 1 ) 304 { 305 pLine++; nCol++; continue; 306 } 307 else *p++ = *pLine++, nCol++; 308 } 309 else if( strchr( "DdEe", *pLine ) ) 310 { 311 if (++exp > 1) 312 { 313 pLine++; nCol++; continue; 314 } 315 // if( toupper( *pLine ) == 'D' ) 316 // eScanType = SbxDOUBLE; 317 *p++ = 'E'; pLine++; nCol++; 318 // Vorzeichen hinter Exponent? 319 if( *pLine == '+' ) 320 pLine++, nCol++; 321 else 322 if( *pLine == '-' ) 323 *p++ = *pLine++, nCol++; 324 } 325 else 326 { 327 *p++ = *pLine++, nCol++; 328 if( comma && !exp ) ncdig++; 329 } 330 if (!exp) ndig++; 331 } 332 *p = 0; 333 aSym = p; bNumber = sal_True; 334 // Komma, Exponent mehrfach vorhanden? 335 if( comma > 1 || exp > 1 ) 336 { aError = '.'; 337 GenError( SbERR_BAD_CHAR_IN_NUMBER ); } 338 339 // #57844 Lokalisierte Funktion benutzen 340 nVal = rtl_math_uStringToDouble( buf, buf+(p-buf), '.', ',', NULL, NULL ); 341 // ALT: nVal = atof( buf ); 342 343 ndig = ndig - comma; 344 if( !comma && !exp ) 345 { 346 if( nVal >= SbxMININT && nVal <= SbxMAXINT ) 347 eScanType = SbxINTEGER; 348 else 349 if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG ) 350 eScanType = SbxLONG; 351 } 352 if( bBufOverflow ) 353 GenError( SbERR_MATH_OVERFLOW ); 354 // zu viele Zahlen für SINGLE? 355 // if (ndig > 15 || ncdig > 6) 356 // eScanType = SbxDOUBLE; 357 // else 358 // if( nVal > SbxMAXSNG || nVal < SbxMINSNG ) 359 // eScanType = SbxDOUBLE; 360 361 // Typkennung? 362 SbxDataType t = GetSuffixType( *pLine ); 363 if( t != SbxVARIANT ) 364 { 365 eScanType = t; 366 pLine++; 367 nCol++; 368 } 369 } 370 371 // Hex/Oktalzahl? Einlesen und konvertieren: 372 else if( *pLine == '&' ) 373 { 374 pLine++; nCol++; 375 sal_Unicode cmp1[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', 0 }; 376 sal_Unicode cmp2[] = { '0', '1', '2', '3', '4', '5', '6', '7', 0 }; 377 sal_Unicode *cmp = cmp1; 378 //char *cmp = "0123456789ABCDEF"; 379 sal_Unicode base = 16; 380 sal_Unicode ndig = 8; 381 sal_Unicode xch = *pLine++ & 0xFF; nCol++; 382 switch( toupper( xch ) ) 383 { 384 case 'O': 385 cmp = cmp2; base = 8; ndig = 11; break; 386 //cmp = "01234567"; base = 8; ndig = 11; break; 387 case 'H': 388 break; 389 default : 390 // Wird als Operator angesehen 391 pLine--; nCol--; nCol1 = nCol-1; aSym = '&'; return SYMBOL; 392 } 393 bNumber = sal_True; 394 long l = 0; 395 int i; 396 sal_Bool bBufOverflow = sal_False; 397 while( BasicSimpleCharClass::isAlphaNumeric( *pLine & 0xFF, bCompatible ) ) 398 { 399 sal_Unicode ch = sal::static_int_cast< sal_Unicode >( 400 toupper( *pLine & 0xFF ) ); 401 pLine++; nCol++; 402 // AB 4.1.1996: Buffer voll, leer weiter scannen 403 if( (p-buf) == (BUF_SIZE-1) ) 404 bBufOverflow = sal_True; 405 else if( String( cmp ).Search( ch ) != STRING_NOTFOUND ) 406 //else if( strchr( cmp, ch ) ) 407 *p++ = ch; 408 else 409 { 410 aError = ch; 411 GenError( SbERR_BAD_CHAR_IN_NUMBER ); 412 } 413 } 414 *p = 0; 415 for( p = buf; *p; p++ ) 416 { 417 i = (*p & 0xFF) - '0'; 418 if( i > 9 ) i -= 7; 419 l = ( l * base ) + i; 420 if( !ndig-- ) 421 { 422 GenError( SbERR_MATH_OVERFLOW ); break; 423 } 424 } 425 if( *pLine == '&' ) pLine++, nCol++; 426 nVal = (double) l; 427 eScanType = ( l >= SbxMININT && l <= SbxMAXINT ) ? SbxINTEGER : SbxLONG; 428 if( bBufOverflow ) 429 GenError( SbERR_MATH_OVERFLOW ); 430 } 431 432 // Strings: 433 else if( *pLine == '"' || *pLine == '[' ) 434 { 435 sal_Unicode cSep = *pLine; 436 if( cSep == '[' ) 437 bSymbol = sal_True, cSep = ']'; 438 short n = nCol+1; 439 while( *pLine ) 440 { 441 do pLine++, nCol++; 442 while( *pLine && ( *pLine != cSep ) ); 443 if( *pLine == cSep ) 444 { 445 pLine++; nCol++; 446 if( *pLine != cSep || cSep == ']' ) break; 447 } else aError = cSep, GenError( SbERR_EXPECTED ); 448 } 449 // If VBA Interop then don't eat the [] chars 450 if ( cSep == ']' && bVBASupportOn ) 451 aSym = aLine.copy( n - 1, nCol - n + 1); 452 else 453 aSym = aLine.copy( n, nCol - n - 1 ); 454 // Doppelte Stringbegrenzer raus 455 String s( cSep ); 456 s += cSep; 457 sal_uInt16 nIdx = 0; 458 do 459 { 460 nIdx = aSym.Search( s, nIdx ); 461 if( nIdx == STRING_NOTFOUND ) 462 break; 463 aSym.Erase( nIdx, 1 ); 464 nIdx++; 465 } 466 while( true ); 467 if( cSep != ']' ) 468 eScanType = ( cSep == '#' ) ? SbxDATE : SbxSTRING; 469 } 470 // ungültige Zeichen: 471 else if( ( *pLine & 0xFF ) >= 0x7F ) 472 { 473 GenError( SbERR_SYNTAX ); pLine++; nCol++; 474 } 475 // andere Gruppen: 476 else 477 { 478 short n = 1; 479 switch( *pLine++ ) 480 { 481 case '<': if( *pLine == '>' || *pLine == '=' ) n = 2; break; 482 case '>': if( *pLine == '=' ) n = 2; break; 483 case ':': if( *pLine == '=' ) n = 2; break; 484 } 485 aSym = aLine.copy( nCol, n ); 486 pLine += n-1; nCol = nCol + n; 487 } 488 489 nCol2 = nCol-1; 490 491 PrevLineCommentLbl: 492 // Comment? 493 if( bPrevLineExtentsComment || (eScanType != SbxSTRING && 494 ( aSym.GetBuffer()[0] == '\'' || aSym.EqualsIgnoreCaseAscii( "REM" ) ) ) ) 495 { 496 bPrevLineExtentsComment = sal_False; 497 aSym = String::CreateFromAscii( "REM" ); 498 sal_uInt16 nLen = String( pLine ).Len(); 499 if( bCompatible && pLine[ nLen - 1 ] == '_' && pLine[ nLen - 2 ] == ' ' ) 500 bPrevLineExtentsComment = sal_True; 501 nCol2 = nCol2 + nLen; 502 pLine = NULL; 503 } 504 return sal_True; 505 506 // Sonst Zeilen-Ende: aber bitte auf '_' testen, ob die 507 // Zeile nicht weitergeht! 508 eoln: 509 if( nCol && *--pLine == '_' ) 510 { 511 pLine = NULL; 512 bool bRes = NextSym(); 513 if( bVBASupportOn && aSym.GetBuffer()[0] == '.' ) 514 { 515 // object _ 516 // .Method 517 // ^^^ <- spaces is legal in MSO VBA 518 OSL_TRACE("*** resetting bSpaces***"); 519 bSpaces = sal_False; 520 } 521 return bRes; 522 } 523 else 524 { 525 pLine = NULL; 526 nLine = nOldLine; 527 nCol1 = nOldCol1; 528 nCol2 = nOldCol2; 529 aSym = '\n'; 530 nColLock = 0; 531 return sal_True; 532 } 533 } 534 535 LetterTable BasicSimpleCharClass::aLetterTable; 536 537 LetterTable::LetterTable( void ) 538 { 539 for( int i = 0 ; i < 256 ; ++i ) 540 IsLetterTab[i] = false; 541 542 IsLetterTab[0xC0] = true; // À , CAPITAL LETTER A WITH GRAVE ACCENT 543 IsLetterTab[0xC1] = true; // Á , CAPITAL LETTER A WITH ACUTE ACCENT 544 IsLetterTab[0xC2] = true; // Â , CAPITAL LETTER A WITH CIRCUMFLEX ACCENT 545 IsLetterTab[0xC3] = true; // Ã , CAPITAL LETTER A WITH TILDE 546 IsLetterTab[0xC4] = true; // Ä , CAPITAL LETTER A WITH DIAERESIS 547 IsLetterTab[0xC5] = true; // Å , CAPITAL LETTER A WITH RING ABOVE 548 IsLetterTab[0xC6] = true; // Æ , CAPITAL LIGATURE AE 549 IsLetterTab[0xC7] = true; // Ç , CAPITAL LETTER C WITH CEDILLA 550 IsLetterTab[0xC8] = true; // È , CAPITAL LETTER E WITH GRAVE ACCENT 551 IsLetterTab[0xC9] = true; // É , CAPITAL LETTER E WITH ACUTE ACCENT 552 IsLetterTab[0xCA] = true; // Ê , CAPITAL LETTER E WITH CIRCUMFLEX ACCENT 553 IsLetterTab[0xCB] = true; // Ë , CAPITAL LETTER E WITH DIAERESIS 554 IsLetterTab[0xCC] = true; // Ì , CAPITAL LETTER I WITH GRAVE ACCENT 555 IsLetterTab[0xCD] = true; // Í , CAPITAL LETTER I WITH ACUTE ACCENT 556 IsLetterTab[0xCE] = true; // Î , CAPITAL LETTER I WITH CIRCUMFLEX ACCENT 557 IsLetterTab[0xCF] = true; // Ï , CAPITAL LETTER I WITH DIAERESIS 558 IsLetterTab[0xD0] = true; // Ð , CAPITAL LETTER ETH 559 IsLetterTab[0xD1] = true; // Ñ , CAPITAL LETTER N WITH TILDE 560 IsLetterTab[0xD2] = true; // Ò , CAPITAL LETTER O WITH GRAVE ACCENT 561 IsLetterTab[0xD3] = true; // Ó , CAPITAL LETTER O WITH ACUTE ACCENT 562 IsLetterTab[0xD4] = true; // Ô , CAPITAL LETTER O WITH CIRCUMFLEX ACCENT 563 IsLetterTab[0xD5] = true; // Õ , CAPITAL LETTER O WITH TILDE 564 IsLetterTab[0xD6] = true; // Ö , CAPITAL LETTER O WITH DIAERESIS 565 IsLetterTab[0xD8] = true; // Ø , CAPITAL LETTER O WITH STROKE 566 IsLetterTab[0xD9] = true; // Ù , CAPITAL LETTER U WITH GRAVE ACCENT 567 IsLetterTab[0xDA] = true; // Ú , CAPITAL LETTER U WITH ACUTE ACCENT 568 IsLetterTab[0xDB] = true; // Û , CAPITAL LETTER U WITH CIRCUMFLEX ACCENT 569 IsLetterTab[0xDC] = true; // Ü , CAPITAL LETTER U WITH DIAERESIS 570 IsLetterTab[0xDD] = true; // Ý , CAPITAL LETTER Y WITH ACUTE ACCENT 571 IsLetterTab[0xDE] = true; // Þ , CAPITAL LETTER THORN 572 IsLetterTab[0xDF] = true; // ß , SMALL LETTER SHARP S 573 IsLetterTab[0xE0] = true; // à , SMALL LETTER A WITH GRAVE ACCENT 574 IsLetterTab[0xE1] = true; // á , SMALL LETTER A WITH ACUTE ACCENT 575 IsLetterTab[0xE2] = true; // â , SMALL LETTER A WITH CIRCUMFLEX ACCENT 576 IsLetterTab[0xE3] = true; // ã , SMALL LETTER A WITH TILDE 577 IsLetterTab[0xE4] = true; // ä , SMALL LETTER A WITH DIAERESIS 578 IsLetterTab[0xE5] = true; // å , SMALL LETTER A WITH RING ABOVE 579 IsLetterTab[0xE6] = true; // æ , SMALL LIGATURE AE 580 IsLetterTab[0xE7] = true; // ç , SMALL LETTER C WITH CEDILLA 581 IsLetterTab[0xE8] = true; // è , SMALL LETTER E WITH GRAVE ACCENT 582 IsLetterTab[0xE9] = true; // é , SMALL LETTER E WITH ACUTE ACCENT 583 IsLetterTab[0xEA] = true; // ê , SMALL LETTER E WITH CIRCUMFLEX ACCENT 584 IsLetterTab[0xEB] = true; // ë , SMALL LETTER E WITH DIAERESIS 585 IsLetterTab[0xEC] = true; // ì , SMALL LETTER I WITH GRAVE ACCENT 586 IsLetterTab[0xED] = true; // í , SMALL LETTER I WITH ACUTE ACCENT 587 IsLetterTab[0xEE] = true; // î , SMALL LETTER I WITH CIRCUMFLEX ACCENT 588 IsLetterTab[0xEF] = true; // ï , SMALL LETTER I WITH DIAERESIS 589 IsLetterTab[0xF0] = true; // ð , SMALL LETTER ETH 590 IsLetterTab[0xF1] = true; // ñ , SMALL LETTER N WITH TILDE 591 IsLetterTab[0xF2] = true; // ò , SMALL LETTER O WITH GRAVE ACCENT 592 IsLetterTab[0xF3] = true; // ó , SMALL LETTER O WITH ACUTE ACCENT 593 IsLetterTab[0xF4] = true; // ô , SMALL LETTER O WITH CIRCUMFLEX ACCENT 594 IsLetterTab[0xF5] = true; // õ , SMALL LETTER O WITH TILDE 595 IsLetterTab[0xF6] = true; // ö , SMALL LETTER O WITH DIAERESIS 596 IsLetterTab[0xF8] = true; // ø , SMALL LETTER O WITH OBLIQUE BAR 597 IsLetterTab[0xF9] = true; // ù , SMALL LETTER U WITH GRAVE ACCENT 598 IsLetterTab[0xFA] = true; // ú , SMALL LETTER U WITH ACUTE ACCENT 599 IsLetterTab[0xFB] = true; // û , SMALL LETTER U WITH CIRCUMFLEX ACCENT 600 IsLetterTab[0xFC] = true; // ü , SMALL LETTER U WITH DIAERESIS 601 IsLetterTab[0xFD] = true; // ý , SMALL LETTER Y WITH ACUTE ACCENT 602 IsLetterTab[0xFE] = true; // þ , SMALL LETTER THORN 603 IsLetterTab[0xFF] = true; // ÿ , SMALL LETTER Y WITH DIAERESIS 604 } 605 606 bool LetterTable::isLetterUnicode( sal_Unicode c ) 607 { 608 static CharClass* pCharClass = NULL; 609 if( pCharClass == NULL ) 610 pCharClass = new CharClass( Application::GetSettings().GetLocale() ); 611 String aStr( c ); 612 bool bRet = pCharClass->isLetter( aStr, 0 ); 613 return bRet; 614 } 615 616 /* vim: set noet sw=4 ts=4: */ 617