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