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