Локализация и POSIX.
Если мы говорим о файле, то в идеологии POSIX, - это просто плоская последовательность байтов. Внутреннее содержимое не стандартизовано никак. Поэтому невозможно определить, какую информацию содержит файл, а если он содержит текстовую информацию -- в какой она кодировке. То же самое можно сказать о потоках : stdin/stdout
-- это потоки байтов (кодов). Кодировка (т.е. соответствие символ-код (CES)) полностью потеряна и нигде не указывается. И POSIX
вовсе не гарантирует, что CES (кодировка) stdin
будет совпадать с текущей локализацией, заданной через LANG=.
Точно тактая же ситуация с терминальным : кодировка терминала совершенно неизвестна приложению.
К сожалению, в стандарте POSIX
поддержка Charset не имеет полностью идеологически стройной и ясной концепции. Понятие Charset существует только для locale API и тех функций, которые зависят от locale.
Более того, в "чистом" POSIX
вообще невозможно
узнать (получить) имя Charset после вызова . Единственный способ, узнать Charset текущей locale
- это воспользоваться не-POSIX функцией XPG
(но определенной в Single UNIX, SVID
и Unix98) : (определена в файле ). Тогда текущий Сharset можно получить так :
#include <locale.h> #include <langinfo.h>
... setlocale(LC_ALL,""); printf ("Current charset = %s\n",nl_langinfo(CODESET)); |
Надо ли говорить, что некоторые UNIX
(например ) не имеют этих XPG-extensions и не имеют функции как таковой вообще. (Что очень странно, поскольку в том же POSIX определена утилита c keyword-ом codeset которая "как-то" это имя определяет...) Например, популярная система до сих пор не имеет функции (как впрочем не имеет и утилиты , увы !).
Еще один способ определения текущего Charset-а - это разбор
переменной окружения . По стандарту POSIX переменная LANG=
задается в форме LANG=language_TERRITORY.Codeset. Например, переменная
(управляющая поведением подсистемы )может иметь "подстановки" :
%L
The value of the LC_MESSAGES category.
%l
The language element from the LC_MESSAGES category.
%t
The territory element from the LC_MESSAGES category.
%c
The codeset element from the LC_MESSAGES category.
Таким образом, если задать LANG="ru_RU.KOI8-R", то мы получим :
%L
= "ru_RU.KOI8-R"
%l
= "ru"
%t
= "RU"
%c
= "KOI8-R"
Исходные тексты этих функций открыты и широко доступны.
Таким образом, установив LANG=ru_RU.KOI8-R
мы получим сообщения на русском языке в кодировке KOI8-R, а установив LANG=ru_RU.ISO_8859-5
- в кодировке ISO. На некоторых системах точно так же работает переменная MANPATH=.
К сожалению, поле Charset - опционально и по стандарту можно использовать сокращенную форму : LANG=ru_RU или даже LANG=ru. (См. ключ -f ). Поэтому, если ваша система это поддерживает, задавайте максимально длинное имя для LANG=
, указывая Charset. (получить список можно по ). К сожалению, само тоже может различаться.
Довольно значительное число ошибок происходит из за того, что в языке С
определен тип переменных char (хотя точнее было бы назвать его : byte). Это во-первых, жестко привязывает нас к 8-ми битным кодировкам. А во-вторых, кодировка не определена. Поэтому, если мы задаем строку (массив char), в которой употребляются символы не ASCII (с кодами >128) : char string[]="Проверка"; -- результат совершенно непредсказуем и непереносим. Еще больше проблем вызывает идея .
Также вызывает удивление существование (и синтаксическая корректность) типов signed / unsigned char (что такое "отрицательный" символ? Вот unsigned short int
-- понятно)... Если вы планируете работу вашей программы в многоязычном окружении, неплохо бы предусмотреть атрибут Сharset у любой строки символов char *. Или полностью переходить на UNICODE (wchar_t) в качестве внутренней кодировки.
Содержание ""