1 /* text.c - Text manipulation functions
2 * Copyright (c) 1995-1997 Stefan Jokisch
4 * This file is part of Frotz.
6 * Frotz is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * Frotz 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
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 LOW_STRING, ABBREVIATION, HIGH_STRING, EMBEDDED_STRING, VOCABULARY
27 extern zword object_name (zword);
28 extern zword get_window_font (zword);
32 static int resolution;
35 * According to Matteo De Luigi <matteo.de.luigi@libero.it>,
36 * 0xab and 0xbb were in each other's proper positions.
39 static zchar zscii_to_latin1[] = {
40 0x0e4, 0x0f6, 0x0fc, 0x0c4, 0x0d6, 0x0dc, 0x0df, 0x0bb,
41 0x0ab, 0x0eb, 0x0ef, 0x0ff, 0x0cb, 0x0cf, 0x0e1, 0x0e9,
42 0x0ed, 0x0f3, 0x0fa, 0x0fd, 0x0c1, 0x0c9, 0x0cd, 0x0d3,
43 0x0da, 0x0dd, 0x0e0, 0x0e8, 0x0ec, 0x0f2, 0x0f9, 0x0c0,
44 0x0c8, 0x0cc, 0x0d2, 0x0d9, 0x0e2, 0x0ea, 0x0ee, 0x0f4,
45 0x0fb, 0x0c2, 0x0ca, 0x0ce, 0x0d4, 0x0db, 0x0e5, 0x0c5,
46 0x0f8, 0x0d8, 0x0e3, 0x0f1, 0x0f5, 0x0c3, 0x0d1, 0x0d5,
47 0x0e6, 0x0c6, 0x0e7, 0x0c7, 0x0fe, 0x0f0, 0x0de, 0x0d0,
48 0x0a3, 0x153, 0x152, 0x0a1, 0x0bf
54 * Initialize text variables.
67 * translate_from_zscii
69 * Map a ZSCII character into Unicode.
73 zchar translate_from_zscii (zbyte c)
79 return ZC_DOUBLE_CLICK;
81 return ZC_SINGLE_CLICK;
83 if (c >= 0x9b && story_id != BEYOND_ZORK) {
85 if (hx_unicode_table != 0) { /* game has its own Unicode table */
89 LOW_BYTE (hx_unicode_table, N)
93 zword addr = hx_unicode_table + 1 + 2 * (c - 0x9b);
96 LOW_WORD (addr, unicode)
105 } else /* game uses standard set */
109 return zscii_to_latin1[c - 0x9b];
116 }/* translate_from_zscii */
121 * Convert a Unicode character to ZSCII, returning 0 on failure.
125 zbyte unicode_to_zscii (zchar c)
129 if (c >= ZC_LATIN1_MIN) {
131 if (hx_unicode_table != 0) { /* game has its own Unicode table */
136 LOW_BYTE (hx_unicode_table, N)
138 for (i = 0x9b; i < 0x9b + N; i++) {
140 zword addr = hx_unicode_table + 1 + 2 * (i - 0x9b);
143 LOW_WORD (addr, unicode)
152 } else { /* game uses standard set */
154 for (i = 0x9b; i <= 0xdf; i++)
155 if (c == zscii_to_latin1[i - 0x9b])
165 }/* unicode_to_zscii */
170 * Map a Unicode character onto the ZSCII alphabet.
174 zbyte translate_to_zscii (zchar c)
177 if (c == ZC_SINGLE_CLICK)
179 if (c == ZC_DOUBLE_CLICK)
181 if (c == ZC_MENU_CLICK)
186 c = unicode_to_zscii (c);
192 }/* translate_to_zscii */
197 * Return a character from one of the three character sets.
201 static zchar alphabet (int set, int index)
203 if (h_version > V1 && set == 2 && index == 1)
204 return 0x0D; /* always newline */
206 if (h_alphabet != 0) { /* game uses its own alphabet */
210 zword addr = h_alphabet + 26 * set + index;
213 return translate_from_zscii (c);
215 } else /* game uses default alphabet */
221 else if (h_version == V1)
222 return " 0123456789.,!?_#'\"/\\<-:()"[index];
224 return " ^0123456789.,!?_#'\"/\\-:()"[index];
231 * Find the number of bytes used for dictionary resolution.
235 static void find_resolution (void)
237 zword dct = h_dictionary;
242 LOW_BYTE (dct, sep_count)
243 dct += 1 + sep_count; /* skip word separators */
244 LOW_BYTE (dct, entry_len)
245 dct += 1; /* skip entry length */
246 LOW_WORD (dct, entry_count)
247 dct += 2; /* get number of entries */
249 if (h_version < V9) {
251 resolution = (h_version <= V3) ? 2 : 3;
258 if (entry_count == 0) {
260 runtime_error (ERR_DICT_LEN);
264 /* check the first word in the dictionary */
268 LOW_WORD (addr, code)
271 } while (!(code & 0x8000) && (addr - dct < entry_len + 1));
273 resolution = (addr - dct) / 2;
277 if (2 * resolution > entry_len) {
279 runtime_error (ERR_DICT_LEN);
283 decoded = (zchar *)malloc (sizeof (zchar) * (3 * resolution) + 1);
284 encoded = (zchar *)malloc (sizeof (zchar) * resolution);
286 }/* find_resolution */
291 * Copy a ZSCII string from the memory to the global "decoded" string.
295 static void load_string (zword addr, zword length)
299 if (resolution == 0) find_resolution();
301 while (i < 3 * resolution)
310 decoded[i++] = translate_from_zscii (c);
312 } else decoded[i++] = 0;
319 * Encode the Unicode text in the global "decoded" string then write
320 * the result to the global "encoded" array. (This is used to look up
321 * words in the dictionary.) Up to V3 the vocabulary resolution is
322 * two, from V4 it is three, and from V9 it is any number of words.
323 * Because each word contains three Z-characters, that makes six or
324 * nine Z-characters respectively. Longer words are chopped to the
325 * proper size, shorter words are are padded out with 5's. For word
326 * completion we pad with 0s and 31s, the minimum and maximum
331 static void encode_text (int padding)
333 static zchar again[] = { 'a', 'g', 'a', 'i', 'n', 0, 0, 0, 0 };
334 static zchar examine[] = { 'e', 'x', 'a', 'm', 'i', 'n', 'e', 0, 0 };
335 static zchar wait[] = { 'w', 'a', 'i', 't', 0, 0, 0, 0, 0 };
342 if (resolution == 0) find_resolution();
344 zchars = (zbyte *)malloc (sizeof (zbyte) * 3 * (resolution + 1));
347 /* Expand abbreviations that some old Infocom games lack */
349 if (option_expand_abbreviations && (h_version <= V8))
351 if (padding == 0x05 && decoded[1] == 0)
353 switch (decoded[0]) {
354 case 'g': ptr = again; break;
355 case 'x': ptr = examine; break;
356 case 'z': ptr = wait; break;
359 /* Translate string to a sequence of Z-characters */
361 while (i < 3 * resolution)
363 if ((c = *ptr++) != 0) {
376 /* Search character in the alphabet */
378 for (set = 0; set < 3; set++)
379 for (index = 0; index < 26; index++)
380 if (c == alphabet (set, index))
383 /* Character not found, store its ZSCII value */
385 c2 = translate_to_zscii (c);
389 zchars[i++] = c2 >> 5;
390 zchars[i++] = c2 & 0x1f;
396 /* Character found, store its index */
399 zchars[i++] = ((h_version <= V2) ? 1 : 3) + set;
401 zchars[i++] = index + 6;
403 } else zchars[i++] = padding;
405 /* Three Z-characters make a 16bit word */
407 for (i = 0; i < resolution; i++)
410 (zchars[3 * i + 0] << 10) |
411 (zchars[3 * i + 1] << 5) |
414 encoded[resolution - 1] |= 0x8000;
421 * z_check_unicode, test if a unicode character can be printed (bit 0) and read (bit 1).
427 void z_check_unicode (void)
434 if ((c == 0x08) || (c == 0x0d) || (c == 0x1b))
440 result = 1; // we support unicode
444 }/* z_check_unicode */
447 * z_encode_text, encode a ZSCII string for use in a dictionary.
449 * zargs[0] = address of text buffer
450 * zargs[1] = length of ASCII string
451 * zargs[2] = offset of ASCII string within the text buffer
452 * zargs[3] = address to store encoded text in
454 * This is a V5+ opcode and therefore the dictionary resolution must be
459 void z_encode_text (void)
463 load_string ((zword) (zargs[0] + zargs[2]), zargs[1]);
467 for (i = 0; i < resolution; i++)
468 storew ((zword) (zargs[3] + 2 * i), encoded[i]);
475 * Convert encoded text to Unicode. The encoded text consists of 16bit
476 * words. Every word holds 3 Z-characters (5 bits each) plus a spare
477 * bit to mark the last word. The Z-characters translate to ZSCII by
478 * looking at the current current character set. Some select another
479 * character set, others refer to abbreviations.
481 * There are several different string types:
483 * LOW_STRING - from the lower 64KB (byte address)
484 * ABBREVIATION - from the abbreviations table (word address)
485 * HIGH_STRING - from the end of the memory map (packed address)
486 * EMBEDDED_STRING - from the instruction stream (at PC)
487 * VOCABULARY - from the dictionary (byte address)
489 * The last type is only used for word completion.
493 #define outchar(c) if (st==VOCABULARY) *ptr++=c; else print_char(c)
495 static void decode_text (enum string_type st, zword addr)
506 ptr = NULL; /* makes compilers shut up */
509 if (resolution == 0) find_resolution();
511 /* Calculate the byte address if necessary */
513 if (st == ABBREVIATION)
515 byte_addr = (long) addr << 1;
517 else if (st == HIGH_STRING) {
520 byte_addr = (long) addr << 1;
521 else if (h_version <= V5)
522 byte_addr = (long) addr << 2;
523 else if (h_version <= V7)
524 byte_addr = ((long) addr << 2) + ((long) h_strings_offset << 3);
525 else if (h_version <= V8)
526 byte_addr = (long) addr << 3;
527 else /* h_version == V9 */ {
528 long indirect = (long) addr << 2;
529 HIGH_LONG(indirect, byte_addr);
532 if (byte_addr >= story_size)
533 runtime_error (ERR_ILL_PRINT_ADDR);
537 /* Loop until a 16bit word has the highest bit set */
539 if (st == VOCABULARY)
546 /* Fetch the next 16bit word */
548 if (st == LOW_STRING || st == VOCABULARY) {
549 LOW_WORD (addr, code)
551 } else if (st == HIGH_STRING || st == ABBREVIATION) {
552 HIGH_WORD (byte_addr, code)
557 /* Read its three Z-characters */
559 for (i = 10; i >= 0; i -= 5) {
565 c = (code >> i) & 0x1f;
569 case 0: /* normal operation */
571 if (shift_state == 2 && c == 6)
574 else if (h_version == V1 && c == 1)
577 else if (h_version >= V2 && shift_state == 2 && c == 7)
581 outchar (alphabet (shift_state, c - 6));
586 else if (h_version >= V2 && c == 1)
589 else if (h_version >= V3 && c <= 3)
594 shift_state = (shift_lock + (c & 1) + 1) % 3;
596 if (h_version <= V2 && c >= 4)
597 shift_lock = shift_state;
603 shift_state = shift_lock;
607 case 1: /* abbreviation */
609 ptr_addr = h_abbreviations + 64 * (prev_c - 1) + 2 * c;
611 LOW_WORD (ptr_addr, abbr_addr)
612 decode_text (ABBREVIATION, abbr_addr);
617 case 2: /* ZSCII character - first part */
622 case 3: /* ZSCII character - second part */
624 zc = (prev_c << 5) | c;
626 if (zc > 767) { /* Unicode escape */
630 if (st == LOW_STRING || st == VOCABULARY) {
633 } else if (st == HIGH_STRING || st == ABBREVIATION) {
634 HIGH_WORD (byte_addr, c2)
639 outchar (c2 ^ 0xFFFF);
644 c2 = translate_from_zscii (zc);
658 } while (!(code & 0x8000));
660 if (st == VOCABULARY)
668 * z_new_line, print a new line.
674 void z_new_line (void)
682 * z_print, print a string embedded in the instruction stream.
691 decode_text (EMBEDDED_STRING, 0);
696 * z_print_addr, print a string from the lower 64KB.
698 * zargs[0] = address of string to print
702 void z_print_addr (void)
705 decode_text (LOW_STRING, zargs[0]);
710 * z_print_char print a single ZSCII character.
712 * zargs[0] = ZSCII character to be printed
716 void z_print_char (void)
719 print_char (translate_from_zscii (zargs[0]));
724 * z_print_form, print a formatted table.
726 * zargs[0] = address of formatted table to be printed
730 void z_print_form (void)
733 zword addr = zargs[0];
739 LOW_WORD (addr, count)
755 print_char (translate_from_zscii (c));
768 * Print a signed 16bit number.
772 void print_num (zword value)
778 if ((short) value < 0) {
780 value = - (short) value;
783 /* Print absolute value */
785 for (i = 10000; i != 0; i /= 10)
786 if (value >= i || i == 1)
787 print_char ('0' + (value / i) % 10);
792 * z_print_num, print a signed number.
794 * zargs[0] = number to print
798 void z_print_num (void)
801 print_num (zargs[0]);
808 * Print an object description.
812 void print_object (zword object)
814 zword addr = object_name (object);
818 LOW_BYTE (addr, length)
822 LOW_WORD (addr, code)
824 if (code == 0x94a5) { /* encoded text 0x94a5 == empty string */
826 print_string ("object#"); /* supply a generic name */
827 print_num (object); /* for anonymous objects */
829 } else decode_text (LOW_STRING, addr);
834 * z_print_obj, print an object description.
836 * zargs[0] = number of object to be printed
840 void z_print_obj (void)
843 print_object (zargs[0]);
848 * z_print_paddr, print the string at the given packed address.
850 * zargs[0] = packed address of string to be printed
854 void z_print_paddr (void)
857 decode_text (HIGH_STRING, zargs[0]);
862 * z_print_ret, print the string at PC, print newline then return true.
868 void z_print_ret (void)
871 decode_text (EMBEDDED_STRING, 0);
880 * Print a string of ASCII characters.
884 void print_string (const char *s)
888 while ((c = *s++) != 0)
904 void z_print_unicode (void)
910 print_char (zargs[0]);
912 }/* z_print_unicode */
917 * Scan a dictionary searching for the given word. The first argument
920 * 0x00 - find the first word which is >= the given one
921 * 0x05 - find the word which exactly matches the given one
922 * 0x1f - find the last word which is <= the given one
924 * The return value is 0 if the search fails.
928 static zword lookup_text (int padding, zword dct)
941 if (resolution == 0) find_resolution();
943 encode_text (padding);
945 LOW_BYTE (dct, sep_count) /* skip word separators */
946 dct += 1 + sep_count;
947 LOW_BYTE (dct, entry_len) /* get length of entries */
949 LOW_WORD (dct, entry_count) /* get number of entries */
952 if ((short) entry_count < 0) { /* bad luck, entries aren't sorted */
954 entry_count = - (short) entry_count;
957 } else sorted = TRUE; /* entries are sorted */
960 upper = entry_count - 1;
962 while (lower <= upper) {
964 if (sorted) /* binary search */
965 entry_number = (lower + upper) / 2;
966 else /* linear search */
967 entry_number = lower;
969 entry_addr = dct + entry_number * entry_len;
971 /* Compare word to dictionary entry */
975 for (i = 0; i < resolution; i++) {
976 LOW_WORD (addr, entry)
977 if (encoded[i] != entry)
982 return entry_addr; /* exact match found, return now */
986 if (sorted) /* binary search */
988 if (encoded[i] > entry)
989 lower = entry_number + 1;
991 upper = entry_number - 1;
993 else lower++; /* linear search */
997 /* No exact match has been found */
1002 entry_number = (padding == 0x00) ? lower : upper;
1004 if (entry_number == -1 || entry_number == entry_count)
1007 return dct + entry_number * entry_len;
1014 * Translate a single word to a token and append it to the token
1015 * buffer. Every token consists of the address of the dictionary
1016 * entry, the length of the word and the offset of the word from
1017 * the start of the text buffer. Unknown words cause empty slots
1018 * if the flag is set (such that the text can be scanned several
1019 * times with different dictionaries); otherwise they are zero.
1023 static void tokenise_text (zword text, zword length, zword from, zword parse, zword dct, bool flag)
1026 zbyte token_max, token_count;
1028 LOW_BYTE (parse, token_max)
1030 LOW_BYTE (parse, token_count)
1032 if (token_count < token_max) { /* sufficient space left for token? */
1034 storeb (parse++, token_count + 1);
1036 load_string ((zword) (text + from), length);
1038 addr = lookup_text (0x05, dct);
1040 if (addr != 0 || !flag) {
1042 parse += 4 * token_count;
1044 storew ((zword) (parse + 0), addr);
1045 storeb ((zword) (parse + 2), length);
1046 storeb ((zword) (parse + 3), from);
1052 }/* tokenise_text */
1057 * Split an input line into words and translate the words to tokens.
1061 void tokenise_line (zword text, zword token, zword dct, bool flag)
1068 length = 0; /* makes compilers shut up */
1070 /* Use standard dictionary if the given dictionary is zero */
1075 /* Remove all tokens before inserting new ones */
1077 storeb ((zword) (token + 1), 0);
1079 /* Move the first pointer across the text buffer searching for the
1080 beginning of a word. If this succeeds, store the position in a
1081 second pointer. Move the first pointer searching for the end of
1082 the word. When it is found, "tokenise" the word. Continue until
1083 the end of the buffer is reached. */
1088 if (h_version >= V5) {
1090 LOW_BYTE (addr1, length)
1099 /* Fetch next ZSCII character */
1103 if (h_version >= V5 && addr1 == text + 2 + length)
1108 /* Check for separator */
1112 LOW_BYTE (sep_addr, sep_count)
1117 LOW_BYTE (sep_addr, separator)
1120 } while (c != separator && --sep_count != 0);
1122 /* This could be the start or the end of a word */
1124 if (sep_count == 0 && c != ' ' && c != 0) {
1129 } else if (addr2 != 0) {
1133 (zword) (addr1 - addr2),
1134 (zword) (addr2 - text),
1141 /* Translate separator (which is a word in its own right) */
1148 (zword) (addr1 - text),
1153 }/* tokenise_line */
1156 * z_tokenise, make a lexical analysis of a ZSCII string.
1158 * zargs[0] = address of string to analyze
1159 * zargs[1] = address of token buffer
1160 * zargs[2] = address of dictionary (optional)
1161 * zargs[3] = set when unknown words cause empty slots (optional)
1165 void z_tokenise (void)
1168 /* Supply default arguments */
1175 /* Call tokenise_line to do the real work */
1177 tokenise_line (zargs[0], zargs[1], zargs[2], zargs[3] != 0);
1184 * Scan the vocabulary to complete the last word on the input line
1185 * (similar to "tcsh" under Unix). The return value is
1187 * 2 ==> completion is impossible
1188 * 1 ==> completion is ambiguous
1189 * 0 ==> completion is successful
1191 * The function also returns a string in its second argument. In case
1192 * of 2, the string is empty; in case of 1, the string is the longest
1193 * extension of the last word on the input line that is common to all
1194 * possible completions (for instance, if the last word on the input
1195 * is "fo" and its only possible completions are "follow" and "folly"
1196 * then the string is "ll"); in case of 0, the string is an extension
1197 * to the last word that results in the only possible completion.
1201 int completion (const zchar *buffer, zchar *result)
1212 if (resolution == 0) find_resolution();
1214 /* Copy last word to "decoded" string */
1218 while ((c = *buffer++) != 0)
1222 if (len < 3 * resolution)
1229 /* Search the dictionary for first and last possible extensions */
1231 minaddr = lookup_text (0x00, h_dictionary);
1232 maxaddr = lookup_text (0x1f, h_dictionary);
1234 if (minaddr == 0 || maxaddr == 0 || minaddr > maxaddr)
1237 /* Copy first extension to "result" string */
1239 decode_text (VOCABULARY, minaddr);
1243 for (i = len; (c = decoded[i]) != 0; i++)
1247 /* Merge second extension with "result" string */
1249 decode_text (VOCABULARY, maxaddr);
1251 for (i = len, ptr = result; (c = decoded[i]) != 0; i++, ptr++)
1252 if (*ptr != c) break;
1255 /* Search was ambiguous or successful */
1257 return (minaddr == maxaddr) ? 0 : 1;
1264 * Convert a Unicode character to lowercase.
1265 * Taken from Zip2000 by Kevin Bracey.
1269 zchar unicode_tolower (zchar c)
1271 const static unsigned char tolower_basic_latin[0x100] = {
1272 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
1273 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
1274 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
1275 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
1276 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
1277 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x5B,0x5C,0x5D,0x5E,0x5F,
1278 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
1279 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
1280 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
1281 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
1282 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
1283 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
1284 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
1285 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xD7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xDF,
1286 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
1287 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
1289 const static unsigned char tolower_latin_extended_a[0x80] = {
1290 0x01,0x01,0x03,0x03,0x05,0x05,0x07,0x07,0x09,0x09,0x0B,0x0B,0x0D,0x0D,0x0F,0x0F,
1291 0x11,0x11,0x13,0x13,0x15,0x15,0x17,0x17,0x19,0x19,0x1B,0x1B,0x1D,0x1D,0x1F,0x1F,
1292 0x21,0x21,0x23,0x23,0x25,0x25,0x27,0x27,0x29,0x29,0x2B,0x2B,0x2D,0x2D,0x2F,0x2F,
1293 0x00,0x31,0x33,0x33,0x35,0x35,0x37,0x37,0x38,0x3A,0x3A,0x3C,0x3C,0x3E,0x3E,0x40,
1294 0x40,0x42,0x42,0x44,0x44,0x46,0x46,0x48,0x48,0x49,0x4B,0x4B,0x4D,0x4D,0x4F,0x4F,
1295 0x51,0x51,0x53,0x53,0x55,0x55,0x57,0x57,0x59,0x59,0x5B,0x5B,0x5D,0x5D,0x5F,0x5F,
1296 0x61,0x61,0x63,0x63,0x65,0x65,0x67,0x67,0x69,0x69,0x6B,0x6B,0x6D,0x6D,0x6F,0x6F,
1297 0x71,0x71,0x73,0x73,0x75,0x75,0x77,0x77,0x00,0x7A,0x7A,0x7C,0x7C,0x7E,0x7E,0x7F
1299 const static unsigned char tolower_greek[0x50] = {
1300 0x80,0x81,0x82,0x83,0x84,0x85,0xAC,0x87,0xAD,0xAE,0xAF,0x8B,0xCC,0x8D,0xCD,0xCE,
1301 0x90,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
1302 0xC0,0xC1,0xA2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xAC,0xAD,0xAE,0xAF,
1303 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
1304 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF
1306 const static unsigned char tolower_cyrillic[0x60] = {
1307 0x00,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
1308 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
1309 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
1310 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
1311 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
1312 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F
1316 c = tolower_basic_latin[c];
1317 else if (c == 0x0130)
1318 c = 0x0069; /* Capital I with dot -> lower case i */
1319 else if (c == 0x0178)
1320 c = 0x00FF; /* Capital Y diaeresis -> lower case y diaeresis */
1321 else if (c < 0x0180)
1322 c = tolower_latin_extended_a[c-0x100] + 0x100;
1323 else if (c >= 0x380 && c < 0x3D0)
1324 c = tolower_greek[c-0x380] + 0x300;
1325 else if (c >= 0x400 && c < 0x460)
1326 c = tolower_cyrillic[c-0x400] + 0x400;