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
SbiScanner(const::rtl::OUString & rBuf,StarBASIC * p)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
~SbiScanner()70 SbiScanner::~SbiScanner()
71 {}
72
LockColumn()73 void SbiScanner::LockColumn()
74 {
75 if( !nColLock++ )
76 nSavedCol1 = nCol1;
77 }
78
UnlockColumn()79 void SbiScanner::UnlockColumn()
80 {
81 if( nColLock )
82 nColLock--;
83 }
84
GenError(SbError code)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
DoesColonFollow()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
GetSuffixType(sal_Unicode c)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. */
lclIsWhitespace(sal_Unicode cChar)154 inline bool lclIsWhitespace( sal_Unicode cChar )
155 {
156 return (cChar == ' ') || (cChar == '\t') || (cChar == '\f');
157 }
158
159 } // namespace
160
NextSym()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
LetterTable(void)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
isLetterUnicode(sal_Unicode c)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