1 /*
2 Copyright (C) 2004-2017,2018 John E. Davis
3
4 This file is part of the S-Lang Library.
5
6 The S-Lang Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
10
11 The S-Lang Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 USA.
20 */
21
22 #include "slinclud.h"
23
24 #include "slang.h"
25 #include "_slang.h"
26
27 #ifdef upcase
28 # undef upcase
29 #endif
30
31 /* The Boyer-Moore search algorthm is used below under the following
32 * conditions:
33 *
34 * 1. The search is case-sensitive.
35 * 3. UTF-8 mode is not active.
36 * 2. The search key contains only of single byte characters.
37 * 4. The multi-byte characters in the key are case-less.
38 *
39 * Otherwise, the search is case-insensitive and the key consists of
40 * multi-byte characters. In this case, a modified BM algorithm is used
41 * _if_ each character in the key is composed of multi-byte characters that
42 * have upper and lower case versions of the same length.
43 *
44 * Otherwise, the search search will be performed in a brute-force manner.
45 */
46
47 typedef struct
48 {
49 SLuchar_Type *key;
50 size_t key_len;
51 size_t fskip_table[256];
52 size_t bskip_table[256];
53 }
54 BoyerMoore_Search_Type;
55
56 typedef struct
57 {
58 SLuchar_Type **lower_chars;
59 SLuchar_Type **upper_chars;
60 SLstrlen_Type nlower_chars;
61 SLstrlen_Type nupper_chars;
62 SLsearch_Type *st;
63 }
64 BruteForce_Search_Type;
65
66 struct _pSLsearch_Type
67 {
68 SLuchar_Type *(*search_fun)(SLsearch_Type *, SLuchar_Type *, SLuchar_Type *, SLuchar_Type *, int);
69 void (*free_fun) (SLsearch_Type *);
70 int flags;
71 size_t match_len;
72 union
73 {
74 BoyerMoore_Search_Type bm;
75 BruteForce_Search_Type bf;
76 }
77 s;
78 };
79
80 /* Simple BM search--- case-sensitive, or case-less, or no UTF-8, or 7-bit ascii */
81 static SLuchar_Type *
bm_search_forward(SLsearch_Type * st,SLuchar_Type * beg,SLuchar_Type * end)82 bm_search_forward (SLsearch_Type *st, SLuchar_Type *beg, SLuchar_Type *end)
83 {
84 register unsigned char char1;
85 unsigned char *pos;
86 size_t *skip_table;
87 SLuchar_Type *key;
88 SLstrlen_Type key_len;
89 int case_fold;
90 BoyerMoore_Search_Type *bm;
91
92 bm = &st->s.bm;
93 key_len = bm->key_len;
94
95 st->match_len = 0;
96
97 if ((key_len > (unsigned int) (end - beg))
98 || (key_len == 0))
99 return NULL;
100
101 case_fold = st->flags & SLSEARCH_CASELESS;
102 key = bm->key;
103 skip_table = bm->fskip_table;
104
105 char1 = key[key_len - 1];
106 beg += (key_len - 1);
107
108 while(1)
109 {
110 SLuchar_Type ch;
111 SLstrlen_Type j;
112
113 while (beg < end)
114 {
115 SLstrlen_Type dbeg;
116 ch = *beg;
117 dbeg = skip_table[ch];
118 if ((dbeg < key_len)
119 && ((ch == char1)
120 || (case_fold && (char1 == UPPER_CASE(ch)))))
121 break;
122 beg += dbeg;
123 }
124 if (beg >= end) return NULL;
125
126 pos = beg - (key_len - 1);
127 for (j = 0; j < key_len; j++)
128 {
129 ch = pos[j];
130 if ((key[j] != ch)
131 && ((case_fold == 0)
132 || (key[j] != UPPER_CASE(ch))))
133 break;
134 }
135
136 if (j == key_len)
137 {
138 st->match_len = key_len;
139 return pos;
140 }
141
142 beg += 1;
143 }
144 }
145
146 static SLuchar_Type *
bm_search_backward(SLsearch_Type * st,SLuchar_Type * beg,SLuchar_Type * start,SLuchar_Type * end)147 bm_search_backward (SLsearch_Type *st,
148 SLuchar_Type *beg, SLuchar_Type *start, SLuchar_Type *end)
149 {
150 SLuchar_Type char1;
151 SLstrlen_Type j, ofs;
152 SLstrlen_Type key_len;
153 SLuchar_Type *key;
154 int case_fold;
155 size_t *skip_table;
156 BoyerMoore_Search_Type *bm;
157
158 st->match_len = 0;
159 bm = &st->s.bm;
160
161 key_len = bm->key_len;
162 if ((key_len > (unsigned int) (end - beg))
163 || (key_len == 0)
164 || (end <= beg)
165 || (start < beg)
166 || (start >= end))
167 return NULL;
168
169 case_fold = st->flags & SLSEARCH_CASELESS;
170 key = bm->key;
171 skip_table = bm->bskip_table;
172
173 if (start + key_len > end)
174 start = end - key_len;
175
176 char1 = key[0];
177
178 while(1)
179 {
180 SLuchar_Type ch;
181
182 while (beg <= start)
183 {
184 ch = *start;
185
186 if ((ch == char1)
187 || (case_fold && (char1 == UPPER_CASE(ch))))
188 break;
189
190 ofs = skip_table[ch];
191 start -= ofs;
192 }
193 if (beg > start) return NULL;
194
195 for (j = 1; j < key_len; j++)
196 {
197 ch = start[j];
198 if ((key[j] != ch)
199 && ((case_fold == 0)
200 || (key[j] != UPPER_CASE(ch))))
201 break;
202 }
203 if (j == key_len)
204 {
205 st->match_len = key_len;
206 return start;
207 }
208 start--;
209 }
210 }
211
bm_search(SLsearch_Type * st,SLuchar_Type * pmin,SLuchar_Type * p,SLuchar_Type * pmax,int dir)212 static SLuchar_Type *bm_search (SLsearch_Type *st,
213 SLuchar_Type *pmin, SLuchar_Type *p, SLuchar_Type *pmax,
214 int dir)
215 {
216 if (dir > 0)
217 return bm_search_forward (st, p, pmax);
218 else
219 return bm_search_backward (st, pmin, p, pmax);
220 }
221
222 /* Return value, if non-NULL returns pointer to the end of the string */
223 static SLuchar_Type *
looking_at_bf(SLuchar_Type * pmin,SLuchar_Type * pmax,SLuchar_Type ** lower_chars,SLstrlen_Type nlower_chars,SLuchar_Type ** upper_chars,SLstrlen_Type nupper_chars)224 looking_at_bf (SLuchar_Type *pmin, SLuchar_Type *pmax,
225 SLuchar_Type **lower_chars, SLstrlen_Type nlower_chars,
226 SLuchar_Type **upper_chars, SLstrlen_Type nupper_chars)
227
228 {
229 unsigned int n;
230
231 n = 0;
232 while ((n < nupper_chars) && (n < nlower_chars))
233 {
234 SLuchar_Type *up, *lo, *p;
235 up = upper_chars[n];
236 lo = lower_chars[n];
237
238 n++;
239
240 p = pmin;
241 while ((p < pmax)
242 && (*up == *p)
243 && (*up != 0))
244 {
245 up++;
246 p++;
247 }
248
249 if (*up == 0)
250 {
251 pmin = p;
252 continue;
253 }
254
255 p = pmin;
256 while ((p < pmax)
257 && (*lo == *p)
258 && (*lo != 0))
259 {
260 lo++;
261 p++;
262 }
263
264 if (*lo == 0)
265 {
266 pmin = p;
267 continue;
268 }
269
270 return NULL;
271 }
272 return pmin;
273 }
274
275 /* Brute force case-insensitive searches */
276 static SLuchar_Type *
bf_search_forward(SLsearch_Type * st,SLuchar_Type * pmin,SLuchar_Type * pmax)277 bf_search_forward (SLsearch_Type *st,
278 SLuchar_Type *pmin, SLuchar_Type *pmax)
279 {
280 SLsearch_Type *bf_st;
281 SLuchar_Type chup, chlo;
282 SLuchar_Type **upper_chars;
283 SLuchar_Type **lower_chars;
284 SLstrlen_Type nupper_chars, nlower_chars;
285
286 bf_st = st->s.bf.st;
287 upper_chars = st->s.bf.upper_chars;
288 lower_chars = st->s.bf.lower_chars;
289 nupper_chars = st->s.bf.nupper_chars;
290 nlower_chars = st->s.bf.nlower_chars;
291
292 chup = upper_chars[0][0];
293 chlo = lower_chars[0][0];
294
295 while (1)
296 {
297 SLuchar_Type *p;
298
299 if (bf_st != NULL)
300 {
301 if (NULL == (pmin = SLsearch_forward (bf_st, pmin, pmax)))
302 {
303 st->match_len = 0;
304 return NULL;
305 }
306 p = pmin + bf_st->match_len;
307 }
308 else
309 {
310 while (pmin < pmax)
311 {
312 if ((*pmin == chup) || (*pmin == chlo))
313 break;
314
315 pmin++;
316 }
317
318 if (pmin >= pmax)
319 {
320 st->match_len = 0;
321 return NULL;
322 }
323
324 p = pmin;
325 }
326
327 p = looking_at_bf (p, pmax, lower_chars, nlower_chars,
328 upper_chars, nupper_chars);
329
330 if (p != NULL)
331 {
332 st->match_len = p - pmin;
333 return pmin;
334 }
335
336 pmin++;
337 }
338 }
339
340 static SLuchar_Type *
bf_search_backward(SLsearch_Type * st,SLuchar_Type * pmin,SLuchar_Type * start,SLuchar_Type * pmax)341 bf_search_backward (SLsearch_Type *st,
342 SLuchar_Type *pmin, SLuchar_Type *start, SLuchar_Type *pmax)
343 {
344 SLsearch_Type *bf_st;
345 SLuchar_Type chup, chlo;
346 SLuchar_Type **upper_chars;
347 SLuchar_Type **lower_chars;
348 SLstrlen_Type nupper_chars, nlower_chars;
349
350 bf_st = st->s.bf.st;
351 upper_chars = st->s.bf.upper_chars;
352 lower_chars = st->s.bf.lower_chars;
353 nupper_chars = st->s.bf.nupper_chars;
354 nlower_chars = st->s.bf.nlower_chars;
355
356 chup = upper_chars[0][0];
357 chlo = lower_chars[0][0];
358
359 while (1)
360 {
361 SLuchar_Type *p;
362
363 if (bf_st != NULL)
364 {
365 if (NULL == (start = SLsearch_backward (bf_st, pmin, start+1, pmax)))
366 {
367 st->match_len = 0;
368 return NULL;
369 }
370 p = start + bf_st->match_len;
371 }
372 else
373 {
374 /* start--; */
375 while (start >= pmin)
376 {
377 if ((*start == chup) || (*start == chlo))
378 break;
379 start--;
380 }
381
382 if (start < pmin)
383 {
384 st->match_len = 0;
385 return NULL;
386 }
387
388 p = start;
389 }
390
391 p = looking_at_bf (p, pmax, lower_chars, nlower_chars,
392 upper_chars, nupper_chars);
393
394 if (p != NULL)
395 {
396 st->match_len = p - start;
397 return start;
398 }
399
400 start--;
401 }
402 }
403
404 static SLuchar_Type *
bf_search(SLsearch_Type * st,SLuchar_Type * pmin,SLuchar_Type * p,SLuchar_Type * pmax,int dir)405 bf_search (SLsearch_Type *st,
406 SLuchar_Type *pmin, SLuchar_Type *p, SLuchar_Type *pmax,
407 int dir)
408 {
409 if (dir > 0)
410 return bf_search_forward (st, p, pmax);
411 else
412 return bf_search_backward (st, pmin, p, pmax);
413 }
414
SLsearch_forward(SLsearch_Type * st,SLuchar_Type * pmin,SLuchar_Type * pmax)415 SLuchar_Type *SLsearch_forward (SLsearch_Type *st,
416 SLuchar_Type *pmin, SLuchar_Type *pmax)
417 {
418 if (st == NULL)
419 return NULL;
420
421 return st->search_fun (st, pmin, pmin, pmax, 1);
422 }
423
SLsearch_backward(SLsearch_Type * st,SLuchar_Type * pmin,SLuchar_Type * p,SLuchar_Type * pmax)424 SLuchar_Type *SLsearch_backward (SLsearch_Type *st, SLuchar_Type *pmin,
425 SLuchar_Type *p, SLuchar_Type *pmax)
426 {
427 if (st == NULL)
428 return NULL;
429
430 /* For the backward search, the first character of the string
431 * is assumed satisfy pmin <= BEG < p
432 * and end satisfies pmin < END <= pmax
433 */
434 return st->search_fun (st, pmin, p-1, pmax, -1);
435 }
436
437 static int Case_Tables_Ok;
438
init_skip_table(SLuchar_Type * key,SLstrlen_Type key_len,size_t * skip_table,int dir,int flags)439 static void init_skip_table (SLuchar_Type *key, SLstrlen_Type key_len,
440 size_t *skip_table, int dir, int flags)
441 {
442 unsigned int i;
443
444 for (i = 0; i < 256; i++)
445 skip_table[i] = key_len;
446
447 if (dir < 0)
448 key += (key_len-1);
449
450 /* For a case-insensitive search, the key here will be uppercased */
451 flags = flags & SLSEARCH_CASELESS;
452 i = 0;
453 while (i < key_len)
454 {
455 i++;
456 skip_table[*key] = key_len - i;
457 if (flags)
458 skip_table[LOWER_CASE(*key)] = key_len - i;
459 key += dir;
460 }
461 }
462
bm_free(SLsearch_Type * st)463 static void bm_free (SLsearch_Type *st)
464 {
465 SLang_free_slstring ((char *) st->s.bm.key);
466 }
467
bf_free(SLsearch_Type * st)468 static void bf_free (SLsearch_Type *st)
469 {
470 SLstrlen_Type i, n;
471 SLuchar_Type **a;
472
473 if (NULL != (a = st->s.bf.lower_chars))
474 {
475 n = st->s.bf.nlower_chars;
476 for (i = 0; i < n; i++)
477 SLang_free_slstring ((char *) a[i]);
478 SLfree ((char *) a);
479 }
480
481 if (NULL != (a = st->s.bf.upper_chars))
482 {
483 n = st->s.bf.nupper_chars;
484 for (i = 0; i < n; i++)
485 SLang_free_slstring ((char *) a[i]);
486 SLfree ((char *) a);
487 }
488 }
489
SLsearch_match_len(SLsearch_Type * st)490 SLstrlen_Type SLsearch_match_len (SLsearch_Type *st)
491 {
492 if (st == NULL)
493 return 0;
494
495 return st->match_len;
496 }
497
SLsearch_delete(SLsearch_Type * st)498 void SLsearch_delete (SLsearch_Type *st)
499 {
500 if (st == NULL)
501 return;
502
503 (*st->free_fun) (st);
504 SLfree ((char *)st);
505 }
506
507 /* This is used if the key is not UTF-8, or it is but the search is case-sensitive */
bm_open_search(SLuchar_Type * key,int flags)508 static SLsearch_Type *bm_open_search (SLuchar_Type *key, int flags)
509 {
510 SLsearch_Type *st;
511 size_t keylen;
512
513 keylen = strlen ((char *)key);
514 if (NULL == (st = (SLsearch_Type *)SLcalloc (1, sizeof (SLsearch_Type))))
515 return NULL;
516
517 st->free_fun = bm_free;
518
519 /* If the search is case-insensitive, then it must either be all ascii, or
520 * it is not unicode. In either case, the UPPER_CASE and LOWER_CASE macros
521 * should be ok to use.
522 */
523 if (flags & SLSEARCH_CASELESS)
524 {
525 char *keyup = SLmake_nstring ((char *)key, keylen);
526 if (keyup != NULL)
527 {
528 unsigned char *k = (unsigned char *)keyup;
529 while (*k != 0)
530 {
531 *k = UPPER_CASE(*k);
532 k++;
533 }
534 st->s.bm.key = (SLuchar_Type *)SLang_create_slstring (keyup);
535 SLfree (keyup);
536 }
537 else st->s.bm.key = NULL;
538 }
539 else st->s.bm.key = (SLuchar_Type*) SLang_create_slstring ((char *)key);
540
541 if (st->s.bm.key == NULL)
542 {
543 SLsearch_delete (st);
544 return NULL;
545 }
546 st->s.bm.key_len = keylen;
547 st->flags = flags;
548
549 st->search_fun = bm_search;
550
551 init_skip_table (st->s.bm.key, st->s.bm.key_len, st->s.bm.fskip_table, 1, flags);
552 init_skip_table (st->s.bm.key, st->s.bm.key_len, st->s.bm.bskip_table, -1, flags);
553 return st;
554 }
555
is_bm_ok(SLuchar_Type * key,SLstrlen_Type len,SLuchar_Type ** non_ascii)556 static int is_bm_ok (SLuchar_Type *key, SLstrlen_Type len, SLuchar_Type **non_ascii)
557 {
558 SLuchar_Type *keymax;
559
560 /* See if the key is ascii-only */
561 keymax = key + len;
562
563 while (key < keymax)
564 {
565 if (*key & 0x80)
566 {
567 *non_ascii = key;
568 return 0;
569 }
570
571 key++;
572 }
573
574 return 1;
575 }
576
make_string_array(SLuchar_Type * u,SLstrlen_Type len,SLuindex_Type * nump)577 static SLuchar_Type **make_string_array (SLuchar_Type *u, SLstrlen_Type len, SLuindex_Type *nump)
578 {
579 SLuchar_Type *umax;
580 SLuchar_Type **a;
581 SLuindex_Type num, i;
582 int ignore_combining = 0;
583
584 num = SLutf8_strlen (u, ignore_combining);
585 if (num == 0)
586 return NULL; /* should not happen */
587
588 if (NULL == (a = (SLuchar_Type **) SLcalloc (sizeof (SLuchar_Type *), num)))
589 return NULL;
590
591 umax = u + len;
592 for (i = 0; i < num; i++)
593 {
594 SLuchar_Type *u1 = SLutf8_skip_char (u, umax);
595 if (NULL == (a[i] = (SLuchar_Type *)SLang_create_nslstring ((char *)u, u1 - u)))
596 goto return_error;
597 u = u1;
598 }
599 *nump = num;
600 return a;
601
602 return_error:
603 for (i = 0; i < num; i++)
604 SLang_free_slstring ((char *) a[i]);
605 SLfree ((char *) a);
606 return NULL;
607 }
608
SLsearch_new(SLuchar_Type * key,int flags)609 SLsearch_Type *SLsearch_new (SLuchar_Type *key, int flags)
610 {
611 SLsearch_Type *st, *bf_st;
612 SLuchar_Type *key_upper, *key_lower, *non_ascii;
613 size_t len, upper_len, lower_len;
614
615 if (Case_Tables_Ok == 0)
616 SLang_init_case_tables ();
617
618 if (key == NULL)
619 return NULL;
620
621 if ((0 == (flags & SLSEARCH_CASELESS))
622 || (0 == (flags & SLSEARCH_UTF8)))
623 return bm_open_search (key, flags);
624
625 /* Otherwise the key is UTF-8 and the search is case-insensitive */
626 len = strlen ((char *)key);
627 key_upper = SLutf8_strup (key, key + len);
628 if (key_upper == NULL)
629 return NULL;
630
631 upper_len = strlen ((char *)key_upper);
632
633 if (is_bm_ok (key_upper, upper_len, &non_ascii))
634 {
635 st = bm_open_search (key_upper, flags);
636 SLang_free_slstring ((char *)key_upper);
637 return st;
638 }
639
640 /* Tricky part */
641
642 if (NULL == (key_lower = SLutf8_strlo (key, key + len)))
643 {
644 SLang_free_slstring ((char *)key_upper);
645 return NULL;
646 }
647
648 lower_len = strlen ((char *)key_lower);
649
650 /* Try a case-less search */
651 if ((lower_len == upper_len)
652 && (0 == strcmp ((char *)key_upper, (char *)key_lower)))
653 {
654 flags &= ~SLSEARCH_CASELESS;
655 st = bm_open_search (key_upper, flags);
656 SLang_free_slstring ((char *)key_upper);
657 SLang_free_slstring ((char *)key_lower);
658 return st;
659 }
660
661 /* Now Perform a brute-force search. */
662
663 /* If the first few characters of the search string are ascii, then
664 * use BM for that portion
665 */
666 bf_st = NULL;
667 if (non_ascii - key_upper >= 3)
668 {
669 SLuchar_Type *key1 = (SLuchar_Type *) SLmake_nstring ((char *)key_upper, non_ascii - key_upper);
670
671 /* ok to propagate NULL below */
672 bf_st = SLsearch_new (key1, flags);
673 SLfree ((char *)key1);
674 if (bf_st == NULL)
675 {
676 SLang_free_slstring ((char *)key_upper);
677 SLang_free_slstring ((char *)key_lower);
678 return NULL;
679 }
680
681 key1 = (SLuchar_Type *) SLang_create_slstring ((char *)non_ascii);
682 non_ascii = key_lower + (non_ascii - key_upper);
683 SLang_free_slstring ((char *)key_upper);
684 key_upper = key1;
685
686 key1 = (SLuchar_Type *)SLang_create_slstring ((char *)non_ascii);
687 SLang_free_slstring ((char *)key_lower);
688 key_lower = key1;
689
690 if ((key_lower == NULL) || (key_upper == NULL))
691 {
692 SLang_free_slstring ((char *)key_upper);
693 SLang_free_slstring ((char *)key_lower);
694 SLsearch_delete (bf_st);
695 return NULL;
696 }
697 upper_len = strlen ((char *)key_upper);
698 lower_len = strlen ((char *)key_lower);
699 }
700
701 st = (SLsearch_Type *)SLcalloc (sizeof (SLsearch_Type), 1);
702 if (st == NULL)
703 goto return_error;
704 st->free_fun = bf_free;
705 st->flags = flags;
706 st->search_fun = bf_search;
707
708 st->s.bf.st = bf_st; bf_st = NULL;
709
710 if (NULL == (st->s.bf.lower_chars = make_string_array (key_lower, lower_len, &st->s.bf.nlower_chars)))
711 goto return_error;
712
713 if (NULL == (st->s.bf.upper_chars = make_string_array (key_upper, upper_len, &st->s.bf.nupper_chars)))
714 goto return_error;
715
716 SLang_free_slstring ((char *)key_upper);
717 SLang_free_slstring ((char *)key_lower);
718 return st;
719
720 return_error:
721 SLsearch_delete (st);
722 SLsearch_delete (bf_st);
723 SLang_free_slstring ((char *)key_upper);
724 SLang_free_slstring ((char *)key_lower);
725 return NULL;
726 }
727
728 /* 8bit clean upper and lowercase tables. These are used _only_ when UTF-8
729 * mode is not active, or when uppercasing ASCII.
730 */
731 unsigned char _pSLChg_LCase_Lut[256] = {0};
732 unsigned char _pSLChg_UCase_Lut[256] = {0};
733
SLang_define_case(int * u,int * l)734 void SLang_define_case (int *u, int *l)
735 {
736 unsigned char up = (unsigned char) *u, dn = (unsigned char) *l;
737
738 _pSLChg_LCase_Lut[up] = dn;
739 _pSLChg_LCase_Lut[dn] = dn;
740 _pSLChg_UCase_Lut[dn] = up;
741 _pSLChg_UCase_Lut[up] = up;
742 }
743
SLang_init_case_tables(void)744 void SLang_init_case_tables (void)
745 {
746 int i;
747 if (Case_Tables_Ok) return;
748
749 for (i = 0; i < 256; i++)
750 {
751 _pSLChg_UCase_Lut[i] = i;
752 _pSLChg_LCase_Lut[i] = i;
753 }
754
755 for (i = 'A'; i <= 'Z'; i++)
756 {
757 int j = i + 32;
758 _pSLChg_UCase_Lut[j] = i;
759 _pSLChg_LCase_Lut[i] = j;
760 }
761 #ifdef PC_SYSTEM
762 /* Initialize for DOS code page 437. */
763 _pSLChg_UCase_Lut[135] = 128; _pSLChg_LCase_Lut[128] = 135;
764 _pSLChg_UCase_Lut[132] = 142; _pSLChg_LCase_Lut[142] = 132;
765 _pSLChg_UCase_Lut[134] = 143; _pSLChg_LCase_Lut[143] = 134;
766 _pSLChg_UCase_Lut[130] = 144; _pSLChg_LCase_Lut[144] = 130;
767 _pSLChg_UCase_Lut[145] = 146; _pSLChg_LCase_Lut[146] = 145;
768 _pSLChg_UCase_Lut[148] = 153; _pSLChg_LCase_Lut[153] = 148;
769 _pSLChg_UCase_Lut[129] = 154; _pSLChg_LCase_Lut[154] = 129;
770 _pSLChg_UCase_Lut[164] = 165; _pSLChg_LCase_Lut[165] = 164;
771 #else
772 /* ISO Latin */
773 for (i = 192; i <= 221; i++)
774 {
775 int j = i + 32;
776 _pSLChg_UCase_Lut[j] = i;
777 _pSLChg_LCase_Lut[i] = j;
778 }
779 _pSLChg_UCase_Lut[215] = 215; _pSLChg_LCase_Lut[215] = 215;
780 _pSLChg_UCase_Lut[223] = 223; _pSLChg_LCase_Lut[223] = 223;
781 _pSLChg_UCase_Lut[247] = 247; _pSLChg_LCase_Lut[247] = 247;
782 _pSLChg_UCase_Lut[255] = 255; _pSLChg_LCase_Lut[255] = 255;
783 #endif
784 Case_Tables_Ok = 1;
785 }
786