#включить "руси.з" // Кодирует символ Unicode в последовательность UTF-8. // Возвращает количество записанных байт (от 1 до 4). цел encode_utf8(символ *буф, uint32_t зн) { стат конст uint32_t МАСКИ[] = { 0x00000000, 0x0000007F, 0x000007FF, 0x0000FFFF, 0x0010FFFF, }; цел длина; если (зн <= 0x7F) длина = 1; иначе если (зн <= 0x7FF) длина = 2; иначе если (зн <= 0xFFFF) длина = 3; иначе если (зн <= 0x10FFFF) длина = 4; иначе возврат 0; если (зн >= 0xD800 && зн <= 0xDFFF) возврат 0; символ врем[4]; цел поз = 0; для (цел ш = 0; ш < длина - 1; ш++) { врем[поз++] = 0x80 | (зн & 0x3F); зн >>= 6; } стат конст uint8_t МЕТКА_ПЕРВОГО[] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, }; врем[поз++] = МЕТКА_ПЕРВОГО[длина] | зн; для (цел ш = 0; ш < длина; ш++) буф[ш] = врем[длина - 1 - ш]; возврат длина; } uint32_t decode_utf8(символ **нов_поз, символ *п) { беззнак символ первый = (беззнак символ)*п; если (первый < 0x80) { *нов_поз = п + 1; возврат первый; } цел длина; uint32_t рез; uint32_t мин_знач; если ((первый & 0xF8) == 0xF0) { длина = 4; рез = первый & 0x07; мин_знач = 0x10000; } иначе если ((первый & 0xF0) == 0xE0) { длина = 3; рез = первый & 0x0F; мин_знач = 0x800; } иначе если ((первый & 0xE0) == 0xC0) { длина = 2; рез = первый & 0x1F; мин_знач = 0x80; } иначе { error_at(п, "некорректная UTF-8 последовательность"); } для (цел ш = 1; ш < длина; ш++) { беззнак символ байт = (беззнак символ)п[ш]; если ((байт & 0xC0) != 0x80) error_at(п, "некорректная UTF-8 последовательность"); рез = (рез << 6) | (байт & 0x3F); } если (рез < мин_знач) error_at(п, "избыточная UTF-8 последовательность"); если (рез >= 0xD800 && рез <= 0xDFFF) error_at(п, "суррогатные пары недопустимы в UTF-8"); если (рез > 0x10FFFF) error_at(п, "кодпоинт превышает U+10FFFF"); *нов_поз = п + длина; возврат рез; } стат бул в_диапазоне(uint32_t *диап, uint32_t зн) { для (цел ш = 0; диап[ш] != (uint32_t)-1; ш += 2) { если (зн >= диап[ш] && зн <= диап[ш + 1]) возврат истина; } возврат ложь; } бул is_ident1(uint32_t зн) { если (зн == '_' || зн == '$') возврат истина; если (зн >= 'a' && зн <= 'z') возврат истина; если (зн >= 'A' && зн <= 'Z') возврат истина; если (зн < 0x80) возврат ложь; если (зн == 0x00A8 || зн == 0x00AA || зн == 0x00AD || зн == 0x00AF) возврат истина; если (зн >= 0x00B2 && зн <= 0x00B5) возврат истина; если (зн >= 0x00B7 && зн <= 0x00BA) возврат истина; если (зн >= 0x00BC && зн <= 0x00BE) возврат истина; если (зн >= 0x00C0 && зн <= 0x00D6) возврат истина; если (зн >= 0x00D8 && зн <= 0x00F6) возврат истина; если (зн >= 0x00F8 && зн <= 0x00FF) возврат истина; если (зн >= 0x0100 && зн <= 0x02FF) возврат истина; если (зн >= 0x0370 && зн <= 0x167F) возврат истина; если (зн >= 0x1681 && зн <= 0x180D) возврат истина; если (зн >= 0x180F && зн <= 0x1DBF) возврат истина; если (зн >= 0x1E00 && зн <= 0x1FFF) возврат истина; если (зн == 0x200B || зн == 0x200D) возврат истина; если (зн >= 0x202A && зн <= 0x202E) возврат истина; если (зн == 0x203F || зн == 0x2040 || зн == 0x2054) возврат истина; если (зн >= 0x2060 && зн <= 0x206F) возврат истина; если (зн >= 0x2070 && зн <= 0x20CF) возврат истина; если (зн >= 0x2100 && зн <= 0x218F) возврат истина; если (зн >= 0x2460 && зн <= 0x24FF) возврат истина; если (зн >= 0x2776 && зн <= 0x2793) возврат истина; если (зн >= 0x2C00 && зн <= 0x2DFF) возврат истина; если (зн >= 0x2E80 && зн <= 0x2FFF) возврат истина; если (зн == 0x3004 || зн == 0x3007) возврат истина; если (зн >= 0x3021 && зн <= 0x302F) возврат истина; если (зн >= 0x3031 && зн <= 0x303F) возврат истина; если (зн >= 0x3040 && зн <= 0xD7FF) возврат истина; если (зн >= 0xF900 && зн <= 0xFD3D) возврат истина; если (зн >= 0xFD40 && зн <= 0xFDCF) возврат истина; если (зн >= 0xFDF0 && зн <= 0xFE1F) возврат истина; если (зн >= 0xFE30 && зн <= 0xFE44) возврат истина; если (зн >= 0xFE47 && зн <= 0xFFFD) возврат истина; если (зн >= 0x10000 && зн <= 0xEFFFD) { стат конст uint32_t НАЧ_ПЛОСКОСТЕЙ[] = { 0x10000, 0x20000, 0x30000, 0x40000, 0x50000, 0x60000, 0x70000, 0x80000, 0x90000, 0xA0000, 0xB0000, 0xC0000, 0xD0000, 0xE0000 }; стат конст цел ЧИСЛО_ПЛОСК = размер(НАЧ_ПЛОСКОСТЕЙ) / размер(НАЧ_ПЛОСКОСТЕЙ[0]); для (цел ш = 0; ш < ЧИСЛО_ПЛОСК; ш++) { если (зн >= НАЧ_ПЛОСКОСТЕЙ[ш] && зн <= НАЧ_ПЛОСКОСТЕЙ[ш] + 0xFFFD) возврат истина; } } если (зн >= 0x0400 && зн <= 0x04FF) возврат истина; если (зн >= 0x0500 && зн <= 0x052F) возврат истина; возврат ложь; } бул is_ident2(uint32_t зн) { если (зн >= '0' && зн <= '9') возврат истина; если (зн == '$') возврат истина; если (is_ident1(зн)) возврат истина; если (зн >= 0x0300 && зн <= 0x036F) возврат истина; если (зн >= 0x1DC0 && зн <= 0x1DFF) возврат истина; если (зн >= 0x20D0 && зн <= 0x20FF) возврат истина; если (зн >= 0xFE20 && зн <= 0xFE2F) возврат истина; возврат ложь; } стат цел ширина_символа(uint32_t зн) { если (зн < 0x20) возврат 0; если (зн == 0x7F) возврат 0; если (зн == 0xA0) возврат 0; если (зн >= 0x0300 && зн <= 0x036F) возврат 0; если (зн >= 0x0483 && зн <= 0x0489) возврат 0; если (зн >= 0x0591 && зн <= 0x05BD) возврат 0; если (зн == 0x05BF || зн == 0x05C1 || зн == 0x05C2 || зн == 0x05C4 || зн == 0x05C5 || зн == 0x05C7) возврат 0; если (зн >= 0x0610 && зн <= 0x061A) возврат 0; если (зн >= 0x064B && зн <= 0x065F) возврат 0; если (зн == 0x0670) возврат 0; если (зн >= 0x06D6 && зн <= 0x06DC) возврат 0; если (зн >= 0x06DF && зн <= 0x06E4) возврат 0; если (зн == 0x06E7 || зн == 0x06E8 || зн == 0x06EA || зн == 0x06ED) возврат 0; если (зн == 0x0711) возврат 0; если (зн >= 0x0730 && зн <= 0x074A) возврат 0; если (зн >= 0x07A6 && зн <= 0x07B0) возврат 0; если (зн >= 0x0901 && зн <= 0x0902) возврат 0; если (зн == 0x093C) возврат 0; если (зн >= 0x0941 && зн <= 0x0948) возврат 0; если (зн == 0x094D) возврат 0; если (зн >= 0x0951 && зн <= 0x0954) возврат 0; если (зн == 0x0962 || зн == 0x0963) возврат 0; если (зн == 0x0981) возврат 0; если (зн == 0x09BC) возврат 0; если (зн == 0x09C1 || зн == 0x09C2 || зн == 0x09C3 || зн == 0x09C4) возврат 0; если (зн == 0x09CD) возврат 0; если (зн == 0x09E2 || зн == 0x09E3) возврат 0; если (зн == 0x0A01 || зн == 0x0A02) возврат 0; если (зн == 0x0A3C) возврат 0; если (зн == 0x0A41 || зн == 0x0A42) возврат 0; если (зн == 0x0A47 || зн == 0x0A48) возврат 0; если (зн >= 0x0A4B && зн <= 0x0A4D) возврат 0; если (зн == 0x0A70 || зн == 0x0A71) возврат 0; если (зн == 0x0A81 || зн == 0x0A82) возврат 0; если (зн == 0x0ABC) возврат 0; если (зн >= 0x0AC1 && зн <= 0x0AC5) возврат 0; если (зн == 0x0AC7 || зн == 0x0AC8) возврат 0; если (зн == 0x0ACD) возврат 0; если (зн == 0x0AE2 || зн == 0x0AE3) возврат 0; если (зн == 0x0B01) возврат 0; если (зн == 0x0B3C) возврат 0; если (зн == 0x0B3F) возврат 0; если (зн == 0x0B41 || зн == 0x0B42 || зн == 0x0B43) возврат 0; если (зн == 0x0B4D) возврат 0; если (зн == 0x0B56) возврат 0; если (зн == 0x0B82) возврат 0; если (зн == 0x0BC0) возврат 0; если (зн == 0x0BCD) возврат 0; если (зн >= 0x0C3E && зн <= 0x0C40) возврат 0; если (зн >= 0x0C46 && зн <= 0x0C48) возврат 0; если (зн >= 0x0C4A && зн <= 0x0C4D) возврат 0; если (зн == 0x0C55 || зн == 0x0C56) возврат 0; если (зн == 0x0CBC) возврат 0; если (зн == 0x0CBF) возврат 0; если (зн == 0x0CC6) возврат 0; если (зн == 0x0CCC || зн == 0x0CCD) возврат 0; если (зн == 0x0CE2 || зн == 0x0CE3) возврат 0; если (зн == 0x0D41 || зн == 0x0D42 || зн == 0x0D43) возврат 0; если (зн == 0x0D4D) возврат 0; если (зн == 0x0DCA) возврат 0; если (зн == 0x0DD2 || зн == 0x0DD3 || зн == 0x0DD4) возврат 0; если (зн == 0x0DD6) возврат 0; если (зн == 0x0E31) возврат 0; если (зн >= 0x0E34 && зн <= 0x0E3A) возврат 0; если (зн >= 0x0E47 && зн <= 0x0E4E) возврат 0; если (зн == 0x0EB1) возврат 0; если (зн >= 0x0EB4 && зн <= 0x0EB9) возврат 0; если (зн == 0x0EBB || зн == 0x0EBC) возврат 0; если (зн >= 0x0EC8 && зн <= 0x0ECD) возврат 0; если (зн == 0x0F18 || зн == 0x0F19) возврат 0; если (зн == 0x0F35) возврат 0; если (зн == 0x0F37) возврат 0; если (зн == 0x0F39) возврат 0; если (зн >= 0x0F71 && зн <= 0x0F7E) возврат 0; если (зн >= 0x0F80 && зн <= 0x0F84) возврат 0; если (зн == 0x0F86 || зн == 0x0F87) возврат 0; если (зн >= 0x0F90 && зн <= 0x0F97) возврат 0; если (зн >= 0x0F99 && зн <= 0x0FBC) возврат 0; если (зн == 0x0FC6) возврат 0; если (зн >= 0x102D && зн <= 0x1030) возврат 0; если (зн == 0x1032) возврат 0; если (зн == 0x1036 || зн == 0x1037) возврат 0; если (зн == 0x1039) возврат 0; если (зн == 0x1058 || зн == 0x1059) возврат 0; если (зн >= 0x1160 && зн <= 0x11FF) возврат 0; если (зн == 0x135F) возврат 0; если (зн == 0x1712 || зн == 0x1713 || зн == 0x1714) возврат 0; если (зн == 0x1732 || зн == 0x1733 || зн == 0x1734) возврат 0; если (зн == 0x1752 || зн == 0x1753) возврат 0; если (зн == 0x1772 || зн == 0x1773) возврат 0; если (зн >= 0x17B4 && зн <= 0x17B5) возврат 0; если (зн >= 0x17B7 && зн <= 0x17BD) возврат 0; если (зн == 0x17C6) возврат 0; если (зн >= 0x17C9 && зн <= 0x17D3) возврат 0; если (зн == 0x17DD) возврат 0; если (зн >= 0x180B && зн <= 0x180D) возврат 0; если (зн == 0x18A9) возврат 0; если (зн == 0x1920 || зн == 0x1921 || зн == 0x1922) возврат 0; если (зн == 0x1927 || зн == 0x1928) возврат 0; если (зн == 0x1932) возврат 0; если (зн == 0x1939 || зн == 0x193A || зн == 0x193B) возврат 0; если (зн == 0x1A17 || зн == 0x1A18) возврат 0; если (зн >= 0x1B00 && зн <= 0x1B03) возврат 0; если (зн == 0x1B34) возврат 0; если (зн >= 0x1B36 && зн <= 0x1B3A) возврат 0; если (зн == 0x1B3C) возврат 0; если (зн == 0x1B42) возврат 0; если (зн >= 0x1B6B && зн <= 0x1B73) возврат 0; если (зн >= 0x1DC0 && зн <= 0x1DCA) возврат 0; если (зн == 0x1DFE || зн == 0x1DFF) возврат 0; если (зн >= 0x200B && зн <= 0x200F) возврат 0; если (зн >= 0x202A && зн <= 0x202E) возврат 0; если (зн >= 0x2060 && зн <= 0x2063) возврат 0; если (зн >= 0x206A && зн <= 0x206F) возврат 0; если (зн >= 0x20D0 && зн <= 0x20EF) возврат 0; если (зн >= 0x302A && зн <= 0x302F) возврат 0; если (зн == 0x3099 || зн == 0x309A) возврат 0; если (зн == 0xA806) возврат 0; если (зн == 0xA80B) возврат 0; если (зн == 0xA825 || зн == 0xA826) возврат 0; если (зн == 0xFB1E) возврат 0; если (зн >= 0xFE00 && зн <= 0xFE0F) возврат 0; если (зн >= 0xFE20 && зн <= 0xFE23) возврат 0; если (зн == 0xFEFF) возврат 0; если (зн >= 0xFFF9 && зн <= 0xFFFB) возврат 0; если (зн == 0x10A01 || зн == 0x10A02 || зн == 0x10A03) возврат 0; если (зн == 0x10A05 || зн == 0x10A06) возврат 0; если (зн >= 0x10A0C && зн <= 0x10A0F) возврат 0; если (зн == 0x10A38 || зн == 0x10A39 || зн == 0x10A3A) возврат 0; если (зн == 0x10A3F) возврат 0; если (зн >= 0x1D167 && зн <= 0x1D169) возврат 0; если (зн >= 0x1D173 && зн <= 0x1D182) возврат 0; если (зн >= 0x1D185 && зн <= 0x1D18B) возврат 0; если (зн >= 0x1D1AA && зн <= 0x1D1AD) возврат 0; если (зн >= 0x1D242 && зн <= 0x1D244) возврат 0; если (зн == 0xE0001) возврат 0; если (зн >= 0xE0020 && зн <= 0xE007F) возврат 0; если (зн >= 0xE0100 && зн <= 0xE01EF) возврат 0; если (зн >= 0x1100 && зн <= 0x115F) возврат 2; если (зн == 0x2329 || зн == 0x232A) возврат 2; если (зн >= 0x2E80 && зн <= 0x303E) возврат 2; если (зн >= 0x3040 && зн <= 0xA4CF) возврат 2; если (зн >= 0xAC00 && зн <= 0xD7A3) возврат 2; если (зн >= 0xF900 && зн <= 0xFAFF) возврат 2; если (зн >= 0xFE10 && зн <= 0xFE19) возврат 2; если (зн >= 0xFE30 && зн <= 0xFE6F) возврат 2; если (зн >= 0xFF00 && зн <= 0xFF60) возврат 2; если (зн >= 0xFFE0 && зн <= 0xFFE6) возврат 2; если (зн >= 0x1F000 && зн <= 0x1F644) возврат 2; если (зн >= 0x20000 && зн <= 0x3FFFD) возврат 2; возврат 1; } цел display_width(символ *п, цел длина) { символ *конец = п + длина; цел шир = 0; пока (п < конец) { uint32_t зн = decode_utf8(&п, п); шир += ширина_символа(зн); } возврат шир; }