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