Понадобилось мне давеча спортировать одно консольное приложение под винды (Win7). Ну что, приложение как приложение, ничего особенного. Ну пользуется юникодом, ну пользуется ESC-последовательностями, казалось бы, делов-то куча. Ан нет.
Засада номер 1: На середине второго десятилетия XXI века надо руками включать юникод (chcp 65001).
Засада номер 2: Если байты UTF-8, относящиеся к одному символу, разорваны на два системных вызова write, то на экране получаем козью морду, а не символ юникода. Пришлось плюнуть и на chcp 65001, и на системный вызов write, и воспользоваться WriteConsoleW (для этого пришлось написать функцию сбора юникода из байтиков, естественно).
Засада номер 3: Из-за большого ума Майкрософт решил не реализовывать ESC-последовательности в консольном окне. Пользуйтесь, дескать, разработчики дорогие, нашим всемогущим console API и не выпендривайтесь.
— Что? Переносимость? Какая в подоконник переносимость?
Ну ладно, так и быть, нашел я https://github.com/adoxa/ansicon
Итого, убил полдня на то, что должно было просто работать™, причем так мало исключительно благодаря ansicon. И так у них всё™
no subject
Date: 2015-01-06 02:55 am (UTC)Консоль в виндах по большей части для обратной совместимости с ДОСом и досообразными утилитами под Windows 3.1. Поэтому полный Юникод там по умолчанию выключен - ну какой в ДОСе может быть Юникод?
В Юниксе виндузятнику тоже бывает не слишком уютно. Во-первых, там нет диска C:... :D
no subject
Date: 2015-01-06 02:58 am (UTC)no subject
Date: 2015-01-06 03:34 am (UTC)no subject
Date: 2015-01-06 03:44 am (UTC)dir "c:/bin"
no subject
Date: 2015-01-06 05:35 am (UTC)no subject
Date: 2015-01-06 02:58 am (UTC)no subject
Date: 2015-01-06 02:59 am (UTC)no subject
Date: 2015-01-06 03:39 am (UTC)no subject
Date: 2015-01-06 05:35 am (UTC)no subject
Date: 2015-01-06 06:59 am (UTC)no subject
Date: 2015-01-06 07:13 am (UTC)no subject
Date: 2015-01-06 07:19 am (UTC)Вместо песни "Валенки" подставить 1), 2) стандартный Unicode шрифт, 3) нестандартный Unicode шрифт.
no subject
Date: 2015-01-06 07:44 am (UTC)no subject
Date: 2015-01-06 09:54 am (UTC)no subject
Date: 2015-01-06 10:21 am (UTC)http://superuser.com/questions/104030/what-font-does-cmd-exe-use-by-default-for-output-in-windows-xp
Если не ручками, то как я уже писал, здравствуй, опа, новый г@д:
http://blogs.microsoft.co.il/pavely/2009/07/23/changing-console-fonts/
no subject
Date: 2015-01-06 03:09 am (UTC)no subject
Date: 2015-01-06 03:41 am (UTC)no subject
Date: 2015-01-06 03:44 am (UTC)no subject
Date: 2015-01-06 04:14 am (UTC)Никогда не пользуюсь системными вызовами, что отрабатывать UTF8. Лучше всего это сделано в библиотеке Qt.
А у меня из-за апгрейда ядра Linux с одного минорного индекса вроде Major.Minor -> Major.Minor + 3 отключился WiFi, и единственный способ получить его снова - грузиться в Major.Minor - 3 нынешний. 3.13.0-40 -> 3.13.0-43 -- позор джунглям!
no subject
Date: 2015-01-06 05:07 am (UTC)no subject
Date: 2015-01-06 05:31 am (UTC)no subject
Date: 2015-01-06 06:18 am (UTC)no subject
Date: 2015-01-06 09:10 am (UTC)no subject
Date: 2015-01-06 03:33 pm (UTC)no subject
Date: 2015-01-06 04:25 am (UTC)no subject
Date: 2015-01-06 05:19 am (UTC)Правильно выводить 16-битный юникод на стандартный вывод так: у stdout включается режим Юникода через _setmode(), и потом туда можно писать через wprintf() и тому подобное. Еще желательно посылать первый символ 0xFEFF (или наоборот 0xFFFE, не помню), иначе если устраивать конвейер, не все программы прочухают юникодность. Для конверсии из UTF-8 есть готовые функции, вроде MultiByteToWideChar() правиальная.
no subject
Date: 2015-01-06 07:03 am (UTC)no subject
Date: 2015-01-06 07:46 am (UTC)no subject
Date: 2015-01-06 09:51 am (UTC)no subject
Date: 2015-01-06 10:12 am (UTC)no subject
Date: 2015-01-06 04:45 pm (UTC)Но все равно не думаю, что SFU/SUA содержит исправленную реализацию write для консоли.
no subject
Date: 2015-01-06 05:42 pm (UTC)no subject
Date: 2015-01-06 05:52 pm (UTC)main() {
char * foo = "Привет\n";
while (*foo) write(1, foo++, 1);
}
В Win7 простой вывод произвольного русского текста в UTF-8 на консоль с помощью команды type вызывает местами появление пар значков "вопросительный знак в квадратике" вместо русской буквы - там, где буферизация разорвала ее пополам.
no subject
Date: 2015-01-06 09:07 pm (UTC)Кстати, а вот скажи как юникодный эксперт, есть ли простой способ обнаружить частичные символы, сканируя строку с хвоста? Чтоб их оторвать и сохранить до следующего вызова.
И бонус, как воткнуть в текст программы строку "Привет\n", чтобы компилятор VS ее не испортил: надо или записать файл как "UTF-8 without signature", и тогда компиятор ее молча прожует, или использовать
#pragma execution_character_set("utf-8")
Если же записать файл как "UTF-8 with signature", компилятор проявит интеллект, скажет, что такие буквы не поддерживаются в кодировке, и заменит их на 0x3ff. Но видимо в "UTF-8 without signature" не получится использовать родные широкие строки (L").
no subject
Date: 2015-01-06 09:35 pm (UTC)Если 0xC0 <= последний_байт < 0xF8, то это потенциальный первый байт частичного символа, и его надо сохранить. В противном случае, если 0x80 <= последний_байт < 0xC0, надо отступать назад максимум на 4 байта, пока встречающиеся байты в этом диапазоне.
Если количество итераций превышено или если первый байт вне диапазона - ASCII, то это ошибка в UTF-8 последовательности, и можно оставить как есть. В противном случае, если в найденном байте количество старших бит 1 равно количеству итераций, то последний юникодный символ в буфере представлен целиком. Если же оно больше, то налицо незавершенный символ, и надо сохранить, начиная с найденного байта до конца.
В юниксе я отлично пишу в файле в формате UTF-8 без сигнатур L"Привет" и получаю массив wchar_t.
no subject
Date: 2015-01-06 10:13 pm (UTC)В смысле, в том, который (0xC0 <= байт < 0xF8)?
> В юниксе я отлично пишу в файле в формате UTF-8 без сигнатур L"Привет" и получаю массив wchar_t.
Это потому что компилятор по умолчанию предполагает кодировку UTF-8. В Виндовсе если поставить такую кодировку во всей системе (но непонятно, как именно), то компилятор тоже будет такое предполагать. Он берет кодировку, выбранную в системе как умолчальную. Чтобы это явно поменять, надо использовать прагму.
no subject
Date: 2015-01-06 10:26 pm (UTC)Ну да. При просмотре вперед, количество старших единичных бит в первом байте означает общее число байтов в UTF-8 коде символа.
no subject
Date: 2015-01-06 10:29 pm (UTC)no subject
Date: 2015-01-06 08:30 am (UTC)no subject
Date: 2015-01-06 09:52 am (UTC)no subject
Date: 2015-01-06 10:54 pm (UTC)no subject
Date: 2015-01-06 03:55 pm (UTC)у меня так нормально работает и в макоси и в виндовсе (и в линуксе наверное тоже, но не проверял еще)
есть обертка для плюсов, называется Boost.Nowide
no subject
Date: 2015-01-06 04:39 pm (UTC)В данном случае код чисто сишный, так что буст не помогает.
no subject
Date: 2015-01-06 10:31 pm (UTC)no subject
Date: 2015-01-06 10:33 pm (UTC)no subject
Date: 2015-01-06 11:12 pm (UTC)низкоуровневые языки заставляют ломать голову над маразмами платформы
no subject
Date: 2015-01-06 11:14 pm (UTC)no subject
Date: 2015-01-09 07:38 pm (UTC)Буфер обмена с юникодной консолью (той самой, текстовой, на которую переключаться с помощью ctrl-alt-F1) в линуксах работает отлично. Даже если делать паузу между байтами UTF-8, всё равно вылезают русские буквы. В виндах просто ошибка в библиотеке. Какой-то идиот не подумал, что UTF-8 может быть разорван пополам.