Согласно стандарту POSIX-2001,
LC_COLLATE
LC_MONETARY
LC_NUMERIC
LC_TIME
LC_MESSAGES
входят alpha (буквы), digits (цифры)
и т.п.
Как правило, значениями перечисленных переменных окружения
являются абсолютные маршрутные имена файлов, содержащих
соответствующие определения. Другой вариант (если значение не начинается с
символа / ) – имя среды.
Расширение XSI стандарта POSIX-2001 уточняет один из
возможных форматов имени
язык[_территория][.кодировка][@модификатор]
Примеры: ru_RU.koi8r, ru_UA.
Модификатор позволяет выбрать конкретный вариант данных о
среде в пределах отдельной категории (скажем, словарный порядок
сравнения в категории LC_COLLATE ). Пример: LC_COLLATE=De_DE@dict.
В каждой реализации определены одна или несколько
языковокультурных сред. Поддержка _POSIX2_LOCALEDEF.
Стандартом POSIX-2001 предусмотрены две "собирательные"
переменные окружения, определяющие сразу все (или почти все) категории
LC_ALL
Значение этой переменной окружения учитывается в первую очередь.
LANG
Значение этой переменной окружения учитывается в последнюю
очередь, если не определены значения переменных вида LC_*.
В любой реализации некоторая среда (POSIX или иная) должна быть
определена как подразумеваемая, т. е. используемая тогда, когда
перечисленные выше переменные окружения не определены или имеют пустые
значения. Это можно сделать, например, путем присваивания LANG=POSIX или LANG=C, после чего подразумеваемой станет
В структуре lconv, описанной во <locale.h>,
содержатся поля, определяющие форматы денежных и числовых величин.
Даже беглый взгляд на перечень этих полей позволяет составить
представление о богатстве возможностей определения
char *currency_symbol; /* Местное обозначение денежной величины */ char *decimal_point; /* Символ, отделяющий целую часть */ /* числа от дробной */ char frac_digits; /* Количество цифр в дробной */ /* части местных денежных величин */ char *grouping; /* Размеры групп цифр при */ /* форматировании чисел */ char *int_curr_symbol; /* Международное обозначение денежной */ /* величины */ char int_frac_digits; /* Количество цифр в дробной части */ /* международных денежных величин */ char int_n_cs_precedes; /* Признак того, что международное */ /* обозначение предшествует отрицательной */ /* денежной величине, а не следует за ней */ char int_n_sep_by_space; /* Признак того, что международное */ /* обозначение отделяется от отрицательной */ /* денежной величины пробелом */ char int_n_sign_posn; /* Позиция знака минус в международных */ /* обозначенияхотрицательных денежных */ /* величин */ char int_p_cs_precedes; /* Признак того, что международное */ /* обозначение предшествует неотрицательной */ /* денежной величине, а не следует за ней */ /* */ char int_p_sep_by_space; /* Признак того, что международное */ /* обозначение отделяется от */ /* неотрицательной денежной величины */ /* пробелом */ char int_p_sign_posn; /* Позиция знака плюс в международных */ /* обозначениях положительных денежных */ /* величин */ char *mon_decimal_point; /* Символ, отделяющий целую часть денежной */ /* величины от дробной */ char *mon_grouping; /* Размеры групп цифр при форматировании */ /* денежных величин */ char *mon_thousands_sep; /* Символ, разделяющий группы цифр в */ /* денежных величинах */ char *negative_sign; /* Знак минус для отрицательных денежных */ /* величин */ char n_cs_precedes; /* Признак того, что местное обозначение */ /* предшествует отрицательной денежной */ /* величине, а не следует за ней */ char n_sep_by_space; /* Признак того, что местное обозначение */ /* отделяется от отрицательной денежной */ /* величины пробелом */ char n_sign_posn; /* Позиция знака минус в местных */ /* обозначениях отрицательных денежных */ /* величин */ char *positive_sign; /* Знак плюс для неотрицательных */ /* денежных величин */ char p_cs_precedes; /* Признак того, что местное обозначение */ /* предшествует неотрицательной денежной */ /* величине, а не следует за ней */ char p_sep_by_space; /* Признак того, что местное обозначение */ /* отделяется от неотрицательной денежной */ /* величины пробелом */ char p_sign_posn; /* Позиция знака плюс в местных */ /* обозначениях положительных денежных */ /* величин */ char *thousands_sep; /* Символ, разделяющий группы цифр в */ /* числовых величинах */
Стандарт POSIX-2001 регламентирует средства опроса и установки
характеристик
Общая логика использования средств
интернационализации/локализации такова: пользователь, присваивая соответствующие значения
описанным выше переменным окружения, идентифицирует свою
языково-культурную среду; приложения могут опросить данные о целевой
среде с помощью функции setlocale() и произвести настройку
интернационализированных компонентов.
Определение localedef
или эквивалентным средством.
copy (см.
далее).
LC_ END и имени, употребленного в качестве заголовка
Первому заголовку могут предшествовать строки,
переопределяющие символ # )
и \ ).
Тело категории состоит из одной или нескольких строк, содержащих
идентификатор и, возможно, следующие за ним операнды. В качестве
идентификатора может выступать как ключевое слово, именующее
отдельный элемент LC_.
Операндами могут быть символы, элементы сравнения и цепочки символов. Цепочки символов заключаются в двойные кавычки, операнды разделяются точками с запятой и, возможно, пробелами.
Символы и элементы сравнения представляются определенными ниже именами. Кроме того, символы могут обозначаться естественным образом или кодами; правда, при этом определение языково-культурной среды теряет в мобильности.
Имена символов заключаются в угловые скобки (например, <A>, <z> и т.п.). Такая конструкция должна в точности совпадать с именем,
определенным в файле отображения символов, который специфицирует
опция -f утилиты localedef.
Реализация должна поддерживать по крайней мере один набор символов и соответствующий файл отображения. Любой набор должен включать в себя все элементы из так называемого мобильного набора символов, определяемого стандартом POSIX-2001 (их имена перечислены в листинге 13.2).
Файл отображения символов имеет довольно простую структуру. Если отвлечься от несущественных деталей, он должен состоять из директив вида
< имя_символа> <код> <комментарий>
Эти директивы заключаются между строками
Эти директивы заключаются между строками
и
END CHARMAP
Перед строкой может располагаться определение имени
набора символов, которое задается директивой
< code_set_name> имя
Фрагмент возможного описания набора символов KOI8-R показан в листинге 13.1.
< code_set_name> KOI8-R <comment_char> % <escape_char> / % version: 1.0 % source: RFC1489 via Gabor Kiss <kissg@sztaki.hu> % and Andrey A. Chernov <ache@astral.msk.su> CHARMAP <U0000> /x00 NULL (NUL) <U0001> /x01 START OF HEADING (SOH) <U0002> /x02 START OF TEXT (STX) . . . <U0020> /x20 SPACE <U0021> /x21 EXCLAMATION MARK . . . <U0030> /x30 DIGIT ZERO <U0031> /x31 DIGIT ONE . . . <U0041> /x41 LATIN CAPITAL LETTER A <U0042> /x42 LATIN CAPITAL LETTER B . . . <U0061> /x61 LATIN SMALL LETTER A <U0062> /x62 LATIN SMALL LETTER B . . . <U044E> /xc0 CYRILLIC SMALL LETTER YU <U0430> /xc1 CYRILLIC SMALL LETTER A <U0431> /xc2 CYRILLIC SMALL LETTER BE . . . <U0429> /xfd CYRILLIC CAPITAL LETTER SHCHA <U0427> /xfe CYRILLIC CAPITAL LETTER CHE <U042A> /xff CYRILLIC CAPITAL LETTER HARD SIGN END CHARMAP
Опишем теперь формат определения категорий языково-культурной среды.
Категория определяет классификацию символов,
преобразование регистра и другие атрибуты. К ней относятся следующие
ключевые слова: upper (прописные буквы; для lower (строчные буквы), alpha (буквы), digit
(цифры), alnum (буквы и цифры), space (пробельные символы; для
cntrl (управляющие символы), punct (знаки
пунктуации), graph (печатные символы за исключением пробела), print
(печатные символы), xdigit (шестнадцатеричные цифры), blank (для
С
charclass позволяет задать имена специфичных
для определяемой среды
toupper открывает определение отображения
малых букв в большие. Операнд этого слова представляет собой пару
символов, заключенных в скобки и разделенных запятой. Аналогичным
образом устроен элемент tolower.
В листинге 13.2 показано определение категории для
LC_CTYPE # POSIX-среда, категория LC_CTYPE # "alpha" по определению есть объединение элементов "upper" и "lower" # "alnum" по определению есть объединение элементов "alpha" и "digit" # "print" по определению есть объединение элементов "alnum", "punct" и <space> # "graph" по определению есть объединение элементов "alnum" и "punct" # upper <A>;<B>;<C>;<D>;<E>;<F>;<G>;<H>;<I>;<J>;<K>;\ <L>;<M>;<N>;<O>;<P>;<Q>;<R>;<S>;<T>;<U>;<V>;<W>;\ <X>;<Y>;<Z> # lower <a>;<b>;<c>;<d>;<e>;<f>;<g>;<h>;<i>;<j>;<k>;\ <l>;<m>;<n>;<o>;<p>;<q>;<r>;<s>;<t>;<u>;<v>;<w>;\ <x>;<y>;<z> # digit <zero>;<one>;<two>;<three>;<four>;<five>;\ <six>;<seven>;<eight>;<nine> # space <tab>;<newline>;<vertical-tab>;<form-feed>;\ <carriage-return>;<space> # cntrl <alert>;<backspace>;<tab>;<newline>;\ <vertical-tab>;<form-feed>;<carriage-return>;\ <NUL>;<SOH>;<STX>;<ETX>;<EOT>;<ENQ>;<ACK>;<SO>;\ <SI>;<DLE>;<DC1>;<DC2>;<DC3>;<DC4>;<NAK>;<SYN>;\ <ETB>;<CAN>;<EM>;<SUB>;<ESC>;<IS4>;<IS3>;<IS2>;\ <IS1>;<DEL> # punct <exclamation-mark>;<quotation-mark>;\ <number-sign>;<dollar-sign>;<percent-sign>;\ <ampersand>;<apostrophe>;<left-parenthesis>;\ <right-parenthesis>;<asterisk>;<plus-sign>;\ <comma>;<hyphen>;<period>;<slash>;<colon>;\ <semicolon>;<less-than-sign>;<equals-sign>;\ <greater-than-sign>;<question-mark>;\ <commercial-at>;<left-square-bracket>;\ <backslash>;<right-square-bracket>;\ <circumflex>;<underscore>;<grave-accent>;\ <left-curly-bracket>;<vertical-line>;\ <right-curly-bracket>;<tilde> # xdigit <zero>;<one>;<two>;<three>;<four>;<five>;\ <six>;<seven>;<eight>;<nine>;<A>;<B>;<C>;<D>;\ <E>;<F>;<a>;<b>;<c>;<d>;<e>;<f> # blank <space>;<tab> # toupper (<a>,<A>);(<b>,<B>);(<c>,<C>);(<d>,<D>);\ (<e>,<E>);(<f>,<F>);(<g>,<G>);(<h>,<H>);\ (<i>,<I>);(<j>,<J>);(<k>,<K>);(<l>,<L>);(<m>,<M>);\ (<n>,<N>);(<o>,<O>);(<p>,<P>);(<q>,<Q>);(<r>,<R>);\ (<s>,<S>);(<t>,<T>);(<u>,<U>);(<v>,<V>);(<w>,<W>);\ (<x>,<X>);(<y>,<Y>);(<z>,<Z>) # tolower (<A>,<a>);(<B>,<b>);(<C>,<c>);(<D>,<d>);\ (<E>,<e>);(<F>,<f>);(<G>,<g>);(<H>,<h>);\ (<I>,<i>);(<J>,<j>);(<K>,<k>);(<L>,<l>);\ (<M>,<m>);(<N>,<n>);(<O>,<o>);(<P>,<p>);\( <Q>,<q>);(<R>,<r>);(<S>,<s>);(<T>,<t>);\ <U>,<u>);(<V>,<v>);(<W>,<w>);(<X>,<x>);(\ <Y>,<y>);(<Z>,<z>) END LC_CTYPE
Категория LC_COLLATE определяет порядок алфавитного сравнения
символов для многочисленных служебных программ ( sort, uniq и т.д.),
регулярных выражений, а также функций strcoll(), strxfrm() и других.
В алфавитном сравнении могут участвовать односимвольные и
многосимвольные элементы. Их порядок задается весами, которых у каждого
элемента может быть несколько (не более COLL_WEIGHTS_MAX ). Первый
вес называется основным. Если при сравнении элементов основные веса
совпали, используются соответственные пары дополнительных – до тех
пор, пока либо не будет обнаружено неравенство, либо не кончатся веса.
Допускается формирование классов эквивалентности – присвоение одного основного веса нескольким элементам сравнения. Поддерживаются также отображения один-ко-многим (один символ отображается в последовательность элементов сравнения).
Разумеется, сравнение цепочек символов начинается с разбиения на элементы сравнения.
Правила алфавитного сравнения и директивы присвоения весов
открываются ключевым словом order_start и завершаются директивой order_end. Подразумеваемым правилом является forward – сравнение
от начала к концу цепочки. Возможен и противоположный порядок
( backward ).
После строки order_start элементы сравнения перечисляются в
порядке возрастания. После элемента может быть задана
последовательность его весов. Веса задаются как относительные, в виде имен других
элементов и определяются позицией этих элементов при перечислении.
Специальный вес IGNORE означает, что данный элемент следует
игнорировать при сравнении цепочек. Многоточие в качестве элемента
сравнения обозначает диапазон от предыдущего до последующего элементов.
Элемент UNDEFINED представляет все, что не было указано явно.
В
Категория LC_MONETARY определяет формат денежных величин.
Входящие в нее элементы именуются аналогично полям приведенной выше
структуры lconv. Например, после ключевого слова currency_symbol
задается цепочка символов, обозначающая местные денежные величины.
Если ключевое слово данной категории отсутствует в файле определения
среды либо его значением является пустая цепочка или -1, значит,
соответствующий элемент в
В
В категории LC_NUMERIC, во многом аналогичной LC_MONETARY,
определяются правила и обозначения, используемые применительно к
числовым данным. Здесь также действует параллель со структурой lconv.
В листинге 13.3 показано определение категории LC_NUMERIC для
LC_NUMERIC # POSIX-среда, категория LC_NUMERIC # decimal_point "<period>" thousands_sep "" grouping -1 # END LC_NUMERIC
Элементы категории LC_TIME определяют интерпретацию
date, а также функций strftime(), strptime()
и некоторых
других. В число поддерживаемых ключевых слов входят abday
(сокращенные названия дней недели, начиная с воскресенья; элемент
соответствует спецификатору %a ), day (полные названия дней недели, %A ), abmon (сокращенные названия месяцев, %b ), mon
(полные названия
месяцев, %B ), d_t_fmt (принятое в данной %c ), d_fmt (принятое в данной среде
представление даты, %x ), t_fmt (принятое в данной среде
представление времени, %X ).
Особым образом устроен элемент era, определяющий способ
отсчета и отображения лет для каждой эры, поддерживаемой
направление:смещение:начальная_дата: конечная_дата:имя_эры:формат_эры
Здесь направление – знак плюс или минус, смещение – ближайший
к начальной дате номер года, начальная_дата – цепочка вида
гггг/мм/дд (год, месяц и число начала эры), конечная_дата – год,
месяц и число конца эры либо цепочки "-*" (конечной датой служит
начало отсчета времени) или "+*" (конечной датой служит конец отсчета
времени), формат_эры – цепочка, используемая при форматировании
номеров года в эре.
Отметим, что точка отсчета может быть как самой ранней, так и самой поздней в эре. Примерами служат две христианские эры – после и до Рождества Христова, соответственно.
В листинге 13.4 показано определение категории LC_TIME для
LC_TIME # POSIX-среда, категория LC_TIME # # Сокращенные названия дней недели (%a) abday "<S><u><n>";"<M><o><n>";"<T><u><e>";\ "<W><e><d>";"<T><h><u>";"<F><r><i>";"<S><a><t>" # # Полные названия дней недели (%A) day "<S><u><n><d><a><y>";\ "<M><o><n><d><a><y>";\ "<T><u><e><s><d><a><y>";\ "<W><e><d><n><e><s><d><a><y>";\ "<T><h><u><r><s><d><a><y>";\ "<F><r><i><d><a>\<y>";\ "<S><a><t><u><r><d><a><y>" # # Сокращенные названия месяцев (%b) abmon "<J><a><n>";"<F><e><b>";"<M><a><r>";\ "<A><p><r>";"<M><a><y>";"<J><u><n>";\ "<J><u><l>";"<A><u><g>";"<S><e><p>";\ "<O><c><t>";"<N><o><v>";"<D><e><c>" # # Полные названия месяцев (%B) mon "<J><a><n><u><a><r><y>"\ "<F><e><b><r><u><a><r><y>";\ "<M><a><r><c><h>";"<A><p><r><i><l>";\ "<M><a><y>";"<J><u><n><e>";\ "<J><u><l><y>";"<A><u><g><u><s><t>";\ "<S><e><p><t><e><m><b><e><r>";\ "<O><c><t><o><b><e><r>";\ "<N><o><v><e><m><b><e><r>";\ "<D><e><c><e><m><b><e><r>" # # Эквивалент AM/PM (%p) "AM";"PM" am_pm "<A><M>";"<P><M>" # # Принятое в POSIX-среде представление даты и времени (%c) # "%a %b %e %H:%M:%S %Y" d_t_fmt "<percent-sign><a><space><percent-sign>\ <b><space><percent-sign><e><space>\ <percent-sign><H><colon><percent-sign>\ <M><colon><percent-sign><S><space>\ <percent-sign><Y>" # # Принятое в POSIX-среде представление даты (%x) "%m/%d/%y" d_fmt "<percent-sign><m><slash><percent-sign><d>\ <slash><percent-sign><y>" # # Принятое в POSIX-среде представление времени (%X) "%H:%M:%S" t_fmt "<percent-sign><H><colon><percent-sign><M>\ <colon><percent-sign><S>" # # Принятое в POSIX-среде 12-часовое представление времени (%r) "%I:%M:%S %p" t_fmt_ampm "<percent-sign><I><colon><percent-sign\ <M><colon><percent-sign><S><space>\ <percent_sign><p>" # END LC_TIME
Категория LC_MESSAGES играет весьма ограниченную роль,
определяя положительные и отрицательные ответы. Соответственно, она
содержит два элемента – yesexpr и noexpr, значениями которых служат
LC_MESSAGES # POSIX-среда, категория LC_MESSAGES # yesexpr "<circumflex><left-square-bracket>\ <y><Y><right-square-bracket>" # noexpr "<circumflex><left-square-bracket>\ <n><N><right-square-bracket>" # END LC_MESSAGES
Для создания целевой localedef:
localedef [-c] [-f файл_отображения_символов]
[-i исходный_файл]
[-u имя_набора_символов]
имя_целевой_среды
Утилита localedef преобразует рассмотренное выше определение
категорий
Исходные данные для localedef поступают из файла с именем
операнда опции -i или со стандартного ввода.
Операнд имя_целевой_среды определяет имя создаваемой среды.
Она может быть как общедоступной, так и приватной, с ограниченным
доступом.
-f является -u можно задать имя нестандартного набора
символов.
Опция -c предписывает генерировать выходной файл даже при
наличии предупреждений.
Аргумент имя_целевой_среды идентифицирует созданную
языково-культурную среду. Если это имя начинается с символа /, оно
интерпретируется как localedef
стандартом не специфицируется); в противном случае
интерпретация имени зависит от реализации, а созданная среда становится
общедоступной.
Для получения информации о locale:
locale [-a | -m] locale [-ck] имя ...
Будучи вызванной без аргументов, утилита locale выдает на
стандартный вывод сводную информацию о среде, которая состоит из
значений соответствующих переменных окружения (описанных выше, а также
дополнительных, определенных, быть может, целевой системой).
Результат может выглядеть так, как показано в листинге 13.6. Кавычки вокруг
значений всех переменных окружения, кроме LANG, означают, что они не
были установлены явным образом, а определены по значению $LANG.
LANG=ru_RU.koi8r LC_CTYPE="ru_RU.koi8r" LC_NUMERIC="ru_RU.koi8r" LC_TIME="ru_RU.koi8r" LC_COLLATE="ru_RU.koi8r" LC_MONETARY="ru_RU.koi8r" LC_MESSAGES="ru_RU.koi8r" LC_PAPER="ru_RU.koi8r" LC_NAME="ru_RU.koi8r" LC_ADDRESS="ru_RU.koi8r" LC_TELEPHONE="ru_RU.koi8r" LC_MEASUREMENT="ru_RU.koi8r" LC_IDENTIFICATION="ru_RU.koi8r" LC_ALL=
При наличии аргументов выдается информация о некоторых (если задано ключевое слово) или обо всех (если указано имя категории) элементах категорий.
Опциям служебной программы locale приписан следующий
смысл.
-a
Выдать информацию обо всех общедоступных языково-культурных
средах (включая
-m
Выдать имена доступных файлов отображения символов.
-c
Выдавать имена выбранных (прямо или косвенно, посредством ключевых слов) категорий, что делает результаты более читабельными, когда они охватывают несколько категорий.
-k
Выдавать имена и значения заданных элементов категорий.
Операнд имя может быть именем категории, элемента категории
(ключевым словом) или зарезервированным словом . В двух
первых случаях выдается информация о поименованной категории или ее
элементе, в последнем – имя файла отображения символов, который был
использован при создании
Приведем еще два примера употребления утилиты locale. Данные
о категории LC_TIME, выдаваемые по команде
locale -ck LC_TIME
могут выглядеть так, как показано в листинге 13.7.
LC_TIME abday="Вск;Пнд;Втр;Срд;Чтв;Птн;Сбт" day="Воскресенье;Понедельник;Вторник;Среда; Четверг;Пятница;Суббота" abmon="Янв;Фев;Мар;Апр;Май;Июн;Июл;Авг;Сен; Окт;Ноя;Дек" mon="Января;Февраля;Марта;Апреля;Мая;Июня; Июля;Августа;Сентября;Октября;Ноября;Декабря" d_t_fmt="%a %d %b %Y %T" d_fmt="%d.%m.%Y" t_fmt="%T" . . . first_weekday=1 first_workday=1 cal_direction=1 date_fmt="%a %b %e %H:%M:%S %Z %Y" time-codeset="KOI8-R"
Второй пример демонстрирует фрагмент интернационализированного варианта shell-процедуры, анализирующей интерактивный ответ пользователя. Предполагается, что ответ является значением переменной response.
if echo "$response" | grep -Eq "$(locale yesexpr)" then echo "Ответ положительный" else echo "Ответ отрицательный" fi
Программная установка и опрос характеристик языково-культурной среды
Мы приступаем к рассмотрению функций, предназначенных для
работы с
Функция setlocale() (см. листинг 13.9) служит для установки
и/или опроса всей
#include <locale.h>
char *setlocale (int category,
const char *locale);
Аргумент category задает категорию ( LC_COLLATE, , LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME ), а если его
значение равно LC_ALL, то и всю среду.
Аргумент locale указывает на цепочку символов, содержащую
требуемые установки для выбранной категории (категорий); в общем случае
ее формат зависит от реализации. Имеется, однако, несколько
предопределенных, стандартизованных цепочек.
"POSIX" или "C"
Специфицирует минимальную языково-культурную среду
( setlocale() такая среда устанавливается по умолчанию при входе в main().
""
Специфицирует зависящую от реализации местную
языково-культурную среду, определяемую значениями переменных окружения LC_* и LANG. Интернационализированная программа должна выполнять вызов
вида
setlocale (LC_ALL, "");
для настройки на местную среду выполнения.
Если значением аргумента locale служит пустой указатель, функция setlocale() опрашивает текущее окружение и возвращает имя
используемой setlocale() для восстановления
соответствующей части
Разумеется, в случае неудачного завершения вызова setlocale()
результатом служит пустой указатель.
Получить детальную информацию о категориях LC_MONETARY и LC_NUMERIC текущей localeconv() (см. листинг 13.10).
#include <locale.h> struct lconv *localeconv (void);
Структура типа lconv была описана выше. Здесь мы отметим лишь
два момента.
Поля, имеющие тип char *, указывают на цепочки символов,
каждая из которых (за исключением *decimal_point ) может иметь вид ""
как признак того, что данное значение в текущей среде недоступно или
имеет нулевую длину.
Поля типа char содержат неотрицательные числа; CHAR_MAX
указывает на то, что данное значение в текущей среде недоступно.
Вызов localeconv() не может кончиться неудачей, однако
следует учитывать, что возвращаемая структура может быть
перезаписана последующими обращениями не только к localeconv(), но
и к setlocale().
Следующая программа (см. листинг 13.11) демонстрирует
использование функций setlocale() и localeconv().
#include <stdio.h>
#include <locale.h>
/* Функция опрашивает и выводит цепочки символов, */
/* ассоциированные с текущей средой и ее */
/* категориями */
void print_curr_locale_data (void) {
/* Массив категорий для setlocale() */
int ctgrs [] = {LC_ALL, LC_COLLATE, LC_CTYPE,
LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME};
/* Массив имен категорий */
char *ctgrnms [] = {"LC_ALL", "LC_COLLATE",
"LC_CTYPE", "LC_MESSAGES", "LC_MONETARY",
"LC_NUMERIC", "LC_TIME"};
unsigned int i;
printf ("Цепочки символов, ассоциированные в
текущей среде с\n");
for (i = 0; i < sizeof (ctgrs) / sizeof (int); i++) {
printf (" %s: %s\n", ctgrnms [i], setlocale
(ctgrs [i], NULL));
}
}
int main (void) {
struct lconv *plc;
/* Убедимся, что подразумеваемой является */
/* POSIX-среда */
printf ("Текущая языково-культурная среда:
подразумеваемая\n");
print_curr_locale_data();
/* Установим местную среду */
(void) setlocale (LC_ALL, "");
/* Опросим и выдадим ее характеристики */
printf ("Текущая языково-культурная среда:
местная\n");
print_curr_locale_data();
plc = localeconv ();
printf ("Некоторые элементы категорий
LC_MONETARY и LC_NUMERIC\n");
printf ("int_curr_symbol: %s\n",
plc->int_curr_symbol);
printf ("currency_symbol: %s\n",
plc->currency_symbol);
printf ("mon_decimal_point: %s\n",
plc->mon_decimal_point);
printf ("decimal_point: %s\n",
plc->decimal_point);
printf ("thousands_sep: %s\n",
plc->thousands_sep);
/* Сделаем "денежную" категорию украинской */
if (setlocale (LC_MONETARY, "ru_UA") == NULL) {
perror ("SETLOCALE");
return (1);
}
printf ("Категория LC_MONETARY переустановлена
для Украины\n");
print_curr_locale_data();
plc = localeconv ();
printf ("Некоторые элементы категории
LC_MONETARY\n");
printf ("int_curr_symbol: %s\n",
plc->int_curr_symbol);
printf ("currency_symbol: %s\n",
plc->currency_symbol);
return 0;
}
Возможный результат работы этой программы показан в листинге 13.12.
Текущая языково-культурная среда: подразумеваемая Цепочки символов, ассоциированные в текущей среде с LC_ALL: C LC_COLLATE: C LC_CTYPE: C LC_MESSAGES: C LC_MONETARY: C LC_NUMERIC: C LC_TIME: C Текущая языково-культурная среда: местная Цепочки символов, ассоциированные в текущей среде с LC_ALL: ru_RU.koi8r LC_COLLATE: ru_RU.koi8r LC_CTYPE: ru_RU.koi8r LC_MESSAGES: ru_RU.koi8r LC_MONETARY: ru_RU.koi8r LC_NUMERIC: ru_RU.koi8r LC_TIME: ru_RU.koi8r Некоторые элементы категорий LC_MONETARY и LC_NUMERIC int_curr_symbol: RUR currency_symbol: РУБ mon_decimal_point: . decimal_point: , thousands_sep: . Категория LC_MONETARY переустановлена для Украины Цепочки символов, ассоциированные в текущей среде с LC_ALL: LC_CTYPE=ru_RU.koi8r;LC_NUMERIC=ru_RU.koi8r; LC_TIME=ru_RU.koi8r;LC_COLLATE=ru_RU.koi8r; LC_MONETARY=ru_UA;LC_MESSAGES=ru_RU.koi8r; LC_PAPER=ru_RU.koi8r;LC_NAME=ru_RU.koi8r; LC_ADDRESS=ru_RU.koi8r;LC_TELEPHONE=ru_RU.koi8r; LC_MEASUREMENT=ru_RU.koi8r; LC_IDENTIFICATION=ru_RU.koi8r LC_COLLATE: ru_RU.koi8r LC_CTYPE: ru_RU.koi8r LC_MESSAGES: ru_RU.koi8r LC_MONETARY: ru_UA LC_NUMERIC: ru_RU.koi8r LC_TIME: ru_RU.koi8r Некоторые элементы категории LC_MONETARY int_curr_symbol: UAH currency_symbol: ГР
Для преобразования денежных величин в цепочку символов в
соответствии с настройками текущей strfmon() (см. листинг 13.13), входящей в
XSI-расширение стандарта POSIX-2001.
#include <monetary.h>
ssize_t strfmon (char *restrict s,
size_t maxsize,
const char *restrict format, ...);
Результат преобразования (длиной не более maxsize байт)
помещается в буфер, на который указывает аргумент s. Само преобразование
выполняется под управлением аргумента format. В формат могут входить
обычные символы, просто копируемые в выходную цепочку, а также
Обязательными являются только первый и последний компоненты. Возможных преобразований два:
i
Преобразовать значение типа double в денежную величину
международного формата.
n
Преобразовать значение типа double в денежную величину
местного формата.
В качестве результата функция strfmon() возвращает количество
байт, помещенное в массив s.
Может показаться, что в деле интернационализации/локализации
категориям LC_MONETARY и LC_NUMERIC повезло больше других,
поскольку для них определена многокомпонентная структура lconv, содержащая
значения всех ключевых слов этих категорий, и функция localeconv(),
позволяющая данную структуру получить. Однако на практике дело
обстоит прямо противоположным образом. Для других категорий настройка приложений
на местную языково-культурную среду сводится к вызову
setlocale (LC_ALL, "");
Всю остальную специфику среды учитывают функции isalpha(), tolower(), strcoll(), strftime() и т.д.,
которыми приложения
могут пользоваться стандартными способами.
В листинге 13.14 показан пример программы, использующей
упомянутые функции. Видно, как меняется их поведение при модификации
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <limits.h>
#include <monetary.h>
#define MY_VALUE 1234.567
int main (void) {
char sbuf [LINE_MAX];
printf ("Текущая языково-культурная среда:
подразумеваемая\n");
printf ("isalpha ('Б'): %d\n", isalpha ('Б'));
printf ("tolower ('Б'): '%c'\n", tolower ('Б'));
printf ("Результат преобразования в денежную
величину числа 1234.567\n");
if (strfmon (sbuf, sizeof (sbuf), "Международное
обозначение: %i\n", MY_VALUE) == -1) {
perror ("STRFMON");
return (1);
}
fputs (sbuf, stdout);
(void) strfmon (sbuf, sizeof (sbuf), "Местное
обозначение: %n\n", MY_VALUE);
fputs (sbuf, stdout);
(void) setlocale (LC_ALL, "");
printf ("Текущая языково-культурная среда: местная\n");
printf ("isalpha ('Б'): %d\n", isalpha ('Б'));
printf ("tolower ('Б'): '%c'\n", tolower ('Б'));
printf ("Результат преобразования в денежную
величину числа 1234.567\n");
(void) strfmon (sbuf, sizeof (sbuf),
"Международное обозначение: %i\n", MY_VALUE);
fputs (sbuf, stdout);
(void) strfmon (sbuf, sizeof (sbuf), "Местное
обозначение: %n\n", MY_VALUE);
fputs (sbuf, stdout);
(void) setlocale (LC_MONETARY, "ru_UA");
printf ("Категория LC_MONETARY переустановлена
для Украины\n");
printf ("Результат преобразования в денежную
величину числа 1234.567\n");
(void) strfmon (sbuf, sizeof (sbuf),
"Международное обозначение: %i\n", MY_VALUE);
fputs (sbuf, stdout);
(void) strfmon (sbuf, sizeof (sbuf), "Местное
обозначение: %n\n", MY_VALUE);
fputs (sbuf, stdout);
return 0;
}
Текущая
isalpha ('Б'): 0
tolower ('Б'): 'Б'
Результат преобразования в денежную величину
числа 1234.567
Международное обозначение: 1234.57
Местное обозначение: 1234.57
Текущая языково-культурная среда: местная
isalpha ('Б'): 1024
tolower ('Б'): 'б'
Результат преобразования в денежную величину
числа 1234.567
Международное обозначение: 1 234.57 RUR
Местное обозначение: 1 234.57 руб
Категория LC_MONETARY переустановлена для
Украины
Результат преобразования в денежную величину
числа 1234.567
Международное обозначение: 1 234.57 UAH
Местное обозначение: 1 234.57 ГР
Если требуется получить детальную информацию обо всех аспектах
nl_langinfo() (см. листинг 13.16), отнесенной стандартом
POSIX-2001 к расширению XSI.
#include <langinfo.h> char *nl_langinfo (nl_item item);
Аргументом функции nl_langinfo() могут служить именованные
константы, определенные в заголовочном файле <langinfo.h>.
В общем и целом они соответствуют описанным выше ключевым словам. В
качестве результата nl_langinfo() возвращает указатель на цепочку
символов, содержащую данные о выбранном элементе среды. Если в
текущей среде этот элемент отсутствует, выдаются данные для
Пример программы, использующей функцию nl_langinfo(),
показан в листинге 13.17, возможные результаты ее работы – в листинге 13.18.
#include <stdio.h>
#include <locale.h>
#include <langinfo.h>
#include <regex.h>
#include <limits.h>
int main (void) {
regex_t cere; /* Скомпилированные расширенные */
/* регулярные выражения */
regex_t ceren;
int reerrcode; /* Код ошибки от regcomp или */
/* regexec */
char reerrbuf [LINE_MAX]; /* Буфер для строк с */
/* сообщениями об ошибках */
char response [LINE_MAX]; /* Буфер для ответа */
/* пользователя */
printf ("Текущая языково-культурная среда:
подразумеваемая\n");
printf ("Элемент YESEXPR категории LC_MESSAGES:
%s\n", nl_langinfo (YESEXPR));
printf ("Элемент MON_1 категории LC_TIME: %s\n",
nl_langinfo (MON_1));
(void) setlocale (LC_ALL, "");
printf ("Текущая языково-культурная среда:
местная\n");
printf ("Элемент YESEXPR категории LC_MESSAGES:
%s\n", nl_langinfo (YESEXPR));
printf ("Элемент MON_1 категории LC_TIME: %s\n",
nl_langinfo (MON_1));
/* Скомпилируем расширенное регулярное */
/* выражение для утвердительного ответа */
if ((reerrcode = regcomp (cere, nl_langinfo
(YESEXPR), REG_EXTENDED | REG_ICASE |
REG_NOSUB )) != 0) {
(void) regerror (reerrcode, cere, reerrbuf,
sizeof (reerrbuf));
fputs (reerrbuf, stderr);
fputc ('\n', stderr);
regfree (cere);
return (reerrcode);
}
/* То же для отрицательного ответа */
if ((reerrcode = regcomp (ceren, nl_langinfo
(NOEXPR), REG_EXTENDED | REG_ICASE |
REG_NOSUB )) != 0) {
(void) regerror (reerrcode, ceren, reerrbuf,
sizeof (reerrbuf));
fputs (reerrbuf, stderr);
fputc ('\n', stderr);
regfree (ceren);
return (reerrcode);
}
fputs ("Вы поддерживаете идею стандартизации
программных интерфейсов? ", stdout);
fgets (response, sizeof (response), stdin);
if (regexec (cere, response, 0, NULL, 0) == 0) {
fputs ("Ответ положительный\n", stdout);
} else if (regexec (ceren, response, 0, NULL, 0) == 0) {
fputs ("Ответ отрицательный\n", stdout);
} else {
fputs ("Ответ уклончивый\n", stdout);
}
regfree (cere);
regfree (ceren);
return 0;
}
Текущая языково-культурная среда: подразумеваемая Элемент YESEXPR категории LC_MESSAGES: ^[yY] Элемент MON_1 категории LC_TIME: January Текущая языково-культурная среда: местная Элемент YESEXPR категории LC_MESSAGES: ^[ДдYy].* Элемент MON_1 категории LC_TIME: Января Вы поддерживаете идею стандартизации программных интерфейсов? Да Ответ положительный
К сожалению, обязательная часть стандарта POSIX-2001 содержит
лишь минимум средств для настройки на целевую среду выдаваемых strerror()
(см. листинг 13.19), которая отображает номера (коды) ошибок в
сообщения, зависящие от LC_MESSAGES.
#include <string.h> char *strerror (int errnum);
Обычно в качестве аргумента этой функции используют errno, но
номера ошибок могут поступать и из произвольного источника.
В листинге 13.20 показан пример программы, выдающей perror() и strerror().
#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <errno.h>
int main (void) {
fprintf (stderr, "Текущая языково-культурная
среда: подразумеваемая\n");
errno = 1;
perror ("PERROR, сообщение номер 1");
fprintf (stderr, "STRERROR, сообщение номер 1:
%s\n", strerror (1));
(void) setlocale (LC_ALL, "");
fprintf (stderr, "Текущая языково-культурная
среда: местная\n");
errno = 1;
perror ("PERROR, сообщение номер 1");
fprintf (stderr, "STRERROR, сообщение номер 1:
%s\n", strerror (1));
(void) setlocale (LC_MESSAGES, "ru_UA");
fprintf (stderr, "Категория LC_MESSAGES
переустановлена для Украины\n");
errno = 1;
perror ("PERROR, сообщение номер 1");
fprintf (stderr, "STRERROR, сообщение номер 1:
%s\n", strerror (1));
return 0;
}
Развитые средства для работы с
Стандарт не специфицирует формат каталогов сообщений, но
предлагает служебную программу gencat для их генерации по исходному
описанию:
gencat каталог файл_сообщений ...
Аргумент каталог задает
Исходное описание может состоять из нескольких файлов сообщений, строки которых, помимо прочих, содержат следующие директивы.
$set идентификатор_набора_сообщений комментарий
Задает [1, NL_SETMAX].
В пределах одного исходного файла сообщений идентификаторы должны
задаваться в порядке возрастания. Подразумеваемым является набор NL_SETD (см. <nl_types.h> ).
идентификатор_сообщения текст_сообщения
[1, NL_MSGMAX]. В пределах одного набора
идентификаторы сообщений задаются в порядке возрастания. Длина текста
сообщения должна лежать в диапазоне [0, NL_TEXTMAX].
Отметим, что генерируемые каталоги сообщений могут иметь двоичный формат и, следовательно, нуждаться в перегенерации при переносе на другие системы. Иными словами, и здесь (как и везде в стандарте POSIX) речь идет о мобильности на уровне исходных текстов.
В прикладной программе работа с каталогами сообщений
осуществляется посредством функций catopen(), catgets() и catclose()
(см. листинг 13.21).
#include <nl_types.h> nl_catd catopen (const char *name, int oflag); char *catgets (nl_catd catd, int set_id, int msg_id, const char *s); int catclose (nl_catd catd);
Функция catopen() открывает каталог сообщений и возвращает
его LANG (если аргумент oflag равен нулю) или LC_MESSAGES (если oflag
равен NL_CAT_LOCALE ).
К сожалению, рекомендации по расположению каталогов сообщений на момент написания данного текста еще не были выработаны. Стандарт POSIX-2001 ограничился замечанием о том, что авторам приложений следует соблюдать осторожность, дабы избежать конфликтов с другими приложениями и стандартными служебными программами.
catopen(), используется в
вызове catgets() для чтения сообщения под номером msg_id из набора с
номером set_id. Аргумент s указывает на подразумеваемую цепочку
символов, которая будет возвращена catgets() в качестве результата,
если запрошенное сообщение не удастся прочитать из каталога.
Функция catclose() закрывает каталог сообщений.
Согласно стандарту POSIX-2001,
LC_COLLATE
LC_MONETARY
LC_NUMERIC
LC_TIME
LC_MESSAGES
входят alpha (буквы), digits (цифры)
и т.п.
Как правило, значениями перечисленных переменных окружения
являются абсолютные маршрутные имена файлов, содержащих
соответствующие определения. Другой вариант (если значение не начинается с
символа / ) – имя среды.
Расширение XSI стандарта POSIX-2001 уточняет один из
возможных форматов имени
язык[_территория][.кодировка][@модификатор]
Примеры: ru_RU.koi8r, ru_UA.
Модификатор позволяет выбрать конкретный вариант данных о
среде в пределах отдельной категории (скажем, словарный порядок
сравнения в категории LC_COLLATE ). Пример: LC_COLLATE=De_DE@dict.
В каждой реализации определены одна или несколько
языковокультурных сред. Поддержка _POSIX2_LOCALEDEF.
Стандартом POSIX-2001 предусмотрены две "собирательные"
переменные окружения, определяющие сразу все (или почти все) категории
LC_ALL
Значение этой переменной окружения учитывается в первую очередь.
LANG
Значение этой переменной окружения учитывается в последнюю
очередь, если не определены значения переменных вида LC_*.
В любой реализации некоторая среда (POSIX или иная) должна быть
определена как подразумеваемая, т. е. используемая тогда, когда
перечисленные выше переменные окружения не определены или имеют пустые
значения. Это можно сделать, например, путем присваивания LANG=POSIX или LANG=C, после чего подразумеваемой станет
В структуре lconv, описанной во <locale.h>,
содержатся поля, определяющие форматы денежных и числовых величин.
Даже беглый взгляд на перечень этих полей позволяет составить
представление о богатстве возможностей определения
char *currency_symbol; /* Местное обозначение денежной величины */ char *decimal_point; /* Символ, отделяющий целую часть */ /* числа от дробной */ char frac_digits; /* Количество цифр в дробной */ /* части местных денежных величин */ char *grouping; /* Размеры групп цифр при */ /* форматировании чисел */ char *int_curr_symbol; /* Международное обозначение денежной */ /* величины */ char int_frac_digits; /* Количество цифр в дробной части */ /* международных денежных величин */ char int_n_cs_precedes; /* Признак того, что международное */ /* обозначение предшествует отрицательной */ /* денежной величине, а не следует за ней */ char int_n_sep_by_space; /* Признак того, что международное */ /* обозначение отделяется от отрицательной */ /* денежной величины пробелом */ char int_n_sign_posn; /* Позиция знака минус в международных */ /* обозначенияхотрицательных денежных */ /* величин */ char int_p_cs_precedes; /* Признак того, что международное */ /* обозначение предшествует неотрицательной */ /* денежной величине, а не следует за ней */ /* */ char int_p_sep_by_space; /* Признак того, что международное */ /* обозначение отделяется от */ /* неотрицательной денежной величины */ /* пробелом */ char int_p_sign_posn; /* Позиция знака плюс в международных */ /* обозначениях положительных денежных */ /* величин */ char *mon_decimal_point; /* Символ, отделяющий целую часть денежной */ /* величины от дробной */ char *mon_grouping; /* Размеры групп цифр при форматировании */ /* денежных величин */ char *mon_thousands_sep; /* Символ, разделяющий группы цифр в */ /* денежных величинах */ char *negative_sign; /* Знак минус для отрицательных денежных */ /* величин */ char n_cs_precedes; /* Признак того, что местное обозначение */ /* предшествует отрицательной денежной */ /* величине, а не следует за ней */ char n_sep_by_space; /* Признак того, что местное обозначение */ /* отделяется от отрицательной денежной */ /* величины пробелом */ char n_sign_posn; /* Позиция знака минус в местных */ /* обозначениях отрицательных денежных */ /* величин */ char *positive_sign; /* Знак плюс для неотрицательных */ /* денежных величин */ char p_cs_precedes; /* Признак того, что местное обозначение */ /* предшествует неотрицательной денежной */ /* величине, а не следует за ней */ char p_sep_by_space; /* Признак того, что местное обозначение */ /* отделяется от неотрицательной денежной */ /* величины пробелом */ char p_sign_posn; /* Позиция знака плюс в местных */ /* обозначениях положительных денежных */ /* величин */ char *thousands_sep; /* Символ, разделяющий группы цифр в */ /* числовых величинах */
Стандарт POSIX-2001 регламентирует средства опроса и установки
характеристик
Общая логика использования средств
интернационализации/локализации такова: пользователь, присваивая соответствующие значения
описанным выше переменным окружения, идентифицирует свою
языково-культурную среду; приложения могут опросить данные о целевой
среде с помощью функции setlocale() и произвести настройку
интернационализированных компонентов.
Определение localedef
или эквивалентным средством.
copy (см.
далее).
LC_ END и имени, употребленного в качестве заголовка
Первому заголовку могут предшествовать строки,
переопределяющие символ # )
и \ ).
Тело категории состоит из одной или нескольких строк, содержащих
идентификатор и, возможно, следующие за ним операнды. В качестве
идентификатора может выступать как ключевое слово, именующее
отдельный элемент LC_.
Операндами могут быть символы, элементы сравнения и цепочки символов. Цепочки символов заключаются в двойные кавычки, операнды разделяются точками с запятой и, возможно, пробелами.
Символы и элементы сравнения представляются определенными ниже именами. Кроме того, символы могут обозначаться естественным образом или кодами; правда, при этом определение языково-культурной среды теряет в мобильности.
Имена символов заключаются в угловые скобки (например, <A>, <z> и т.п.). Такая конструкция должна в точности совпадать с именем,
определенным в файле отображения символов, который специфицирует
опция -f утилиты localedef.
Реализация должна поддерживать по крайней мере один набор символов и соответствующий файл отображения. Любой набор должен включать в себя все элементы из так называемого мобильного набора символов, определяемого стандартом POSIX-2001 (их имена перечислены в листинге 13.2).
Файл отображения символов имеет довольно простую структуру. Если отвлечься от несущественных деталей, он должен состоять из директив вида
< имя_символа> <код> <комментарий>
Эти директивы заключаются между строками
Эти директивы заключаются между строками
и
END CHARMAP
Перед строкой может располагаться определение имени
набора символов, которое задается директивой
< code_set_name> имя
Фрагмент возможного описания набора символов KOI8-R показан в листинге 13.1.
< code_set_name> KOI8-R <comment_char> % <escape_char> / % version: 1.0 % source: RFC1489 via Gabor Kiss <kissg@sztaki.hu> % and Andrey A. Chernov <ache@astral.msk.su> CHARMAP <U0000> /x00 NULL (NUL) <U0001> /x01 START OF HEADING (SOH) <U0002> /x02 START OF TEXT (STX) . . . <U0020> /x20 SPACE <U0021> /x21 EXCLAMATION MARK . . . <U0030> /x30 DIGIT ZERO <U0031> /x31 DIGIT ONE . . . <U0041> /x41 LATIN CAPITAL LETTER A <U0042> /x42 LATIN CAPITAL LETTER B . . . <U0061> /x61 LATIN SMALL LETTER A <U0062> /x62 LATIN SMALL LETTER B . . . <U044E> /xc0 CYRILLIC SMALL LETTER YU <U0430> /xc1 CYRILLIC SMALL LETTER A <U0431> /xc2 CYRILLIC SMALL LETTER BE . . . <U0429> /xfd CYRILLIC CAPITAL LETTER SHCHA <U0427> /xfe CYRILLIC CAPITAL LETTER CHE <U042A> /xff CYRILLIC CAPITAL LETTER HARD SIGN END CHARMAP
Опишем теперь формат определения категорий языково-культурной среды.
Категория определяет классификацию символов,
преобразование регистра и другие атрибуты. К ней относятся следующие
ключевые слова: upper (прописные буквы; для lower (строчные буквы), alpha (буквы), digit
(цифры), alnum (буквы и цифры), space (пробельные символы; для
cntrl (управляющие символы), punct (знаки
пунктуации), graph (печатные символы за исключением пробела), print
(печатные символы), xdigit (шестнадцатеричные цифры), blank (для
С
charclass позволяет задать имена специфичных
для определяемой среды
toupper открывает определение отображения
малых букв в большие. Операнд этого слова представляет собой пару
символов, заключенных в скобки и разделенных запятой. Аналогичным
образом устроен элемент tolower.
В листинге 13.2 показано определение категории для
LC_CTYPE # POSIX-среда, категория LC_CTYPE # "alpha" по определению есть объединение элементов "upper" и "lower" # "alnum" по определению есть объединение элементов "alpha" и "digit" # "print" по определению есть объединение элементов "alnum", "punct" и <space> # "graph" по определению есть объединение элементов "alnum" и "punct" # upper <A>;<B>;<C>;<D>;<E>;<F>;<G>;<H>;<I>;<J>;<K>;\ <L>;<M>;<N>;<O>;<P>;<Q>;<R>;<S>;<T>;<U>;<V>;<W>;\ <X>;<Y>;<Z> # lower <a>;<b>;<c>;<d>;<e>;<f>;<g>;<h>;<i>;<j>;<k>;\ <l>;<m>;<n>;<o>;<p>;<q>;<r>;<s>;<t>;<u>;<v>;<w>;\ <x>;<y>;<z> # digit <zero>;<one>;<two>;<three>;<four>;<five>;\ <six>;<seven>;<eight>;<nine> # space <tab>;<newline>;<vertical-tab>;<form-feed>;\ <carriage-return>;<space> # cntrl <alert>;<backspace>;<tab>;<newline>;\ <vertical-tab>;<form-feed>;<carriage-return>;\ <NUL>;<SOH>;<STX>;<ETX>;<EOT>;<ENQ>;<ACK>;<SO>;\ <SI>;<DLE>;<DC1>;<DC2>;<DC3>;<DC4>;<NAK>;<SYN>;\ <ETB>;<CAN>;<EM>;<SUB>;<ESC>;<IS4>;<IS3>;<IS2>;\ <IS1>;<DEL> # punct <exclamation-mark>;<quotation-mark>;\ <number-sign>;<dollar-sign>;<percent-sign>;\ <ampersand>;<apostrophe>;<left-parenthesis>;\ <right-parenthesis>;<asterisk>;<plus-sign>;\ <comma>;<hyphen>;<period>;<slash>;<colon>;\ <semicolon>;<less-than-sign>;<equals-sign>;\ <greater-than-sign>;<question-mark>;\ <commercial-at>;<left-square-bracket>;\ <backslash>;<right-square-bracket>;\ <circumflex>;<underscore>;<grave-accent>;\ <left-curly-bracket>;<vertical-line>;\ <right-curly-bracket>;<tilde> # xdigit <zero>;<one>;<two>;<three>;<four>;<five>;\ <six>;<seven>;<eight>;<nine>;<A>;<B>;<C>;<D>;\ <E>;<F>;<a>;<b>;<c>;<d>;<e>;<f> # blank <space>;<tab> # toupper (<a>,<A>);(<b>,<B>);(<c>,<C>);(<d>,<D>);\ (<e>,<E>);(<f>,<F>);(<g>,<G>);(<h>,<H>);\ (<i>,<I>);(<j>,<J>);(<k>,<K>);(<l>,<L>);(<m>,<M>);\ (<n>,<N>);(<o>,<O>);(<p>,<P>);(<q>,<Q>);(<r>,<R>);\ (<s>,<S>);(<t>,<T>);(<u>,<U>);(<v>,<V>);(<w>,<W>);\ (<x>,<X>);(<y>,<Y>);(<z>,<Z>) # tolower (<A>,<a>);(<B>,<b>);(<C>,<c>);(<D>,<d>);\ (<E>,<e>);(<F>,<f>);(<G>,<g>);(<H>,<h>);\ (<I>,<i>);(<J>,<j>);(<K>,<k>);(<L>,<l>);\ (<M>,<m>);(<N>,<n>);(<O>,<o>);(<P>,<p>);\( <Q>,<q>);(<R>,<r>);(<S>,<s>);(<T>,<t>);\ <U>,<u>);(<V>,<v>);(<W>,<w>);(<X>,<x>);(\ <Y>,<y>);(<Z>,<z>) END LC_CTYPE
Категория LC_COLLATE определяет порядок алфавитного сравнения
символов для многочисленных служебных программ ( sort, uniq и т.д.),
регулярных выражений, а также функций strcoll(), strxfrm() и других.
В алфавитном сравнении могут участвовать односимвольные и
многосимвольные элементы. Их порядок задается весами, которых у каждого
элемента может быть несколько (не более COLL_WEIGHTS_MAX ). Первый
вес называется основным. Если при сравнении элементов основные веса
совпали, используются соответственные пары дополнительных – до тех
пор, пока либо не будет обнаружено неравенство, либо не кончатся веса.
Допускается формирование классов эквивалентности – присвоение одного основного веса нескольким элементам сравнения. Поддерживаются также отображения один-ко-многим (один символ отображается в последовательность элементов сравнения).
Разумеется, сравнение цепочек символов начинается с разбиения на элементы сравнения.
Правила алфавитного сравнения и директивы присвоения весов
открываются ключевым словом order_start и завершаются директивой order_end. Подразумеваемым правилом является forward – сравнение
от начала к концу цепочки. Возможен и противоположный порядок
( backward ).
После строки order_start элементы сравнения перечисляются в
порядке возрастания. После элемента может быть задана
последовательность его весов. Веса задаются как относительные, в виде имен других
элементов и определяются позицией этих элементов при перечислении.
Специальный вес IGNORE означает, что данный элемент следует
игнорировать при сравнении цепочек. Многоточие в качестве элемента
сравнения обозначает диапазон от предыдущего до последующего элементов.
Элемент UNDEFINED представляет все, что не было указано явно.
В
Категория LC_MONETARY определяет формат денежных величин.
Входящие в нее элементы именуются аналогично полям приведенной выше
структуры lconv. Например, после ключевого слова currency_symbol
задается цепочка символов, обозначающая местные денежные величины.
Если ключевое слово данной категории отсутствует в файле определения
среды либо его значением является пустая цепочка или -1, значит,
соответствующий элемент в
В
В категории LC_NUMERIC, во многом аналогичной LC_MONETARY,
определяются правила и обозначения, используемые применительно к
числовым данным. Здесь также действует параллель со структурой lconv.
В листинге 13.3 показано определение категории LC_NUMERIC для
LC_NUMERIC # POSIX-среда, категория LC_NUMERIC # decimal_point "<period>" thousands_sep "" grouping -1 # END LC_NUMERIC
Элементы категории LC_TIME определяют интерпретацию
date, а также функций strftime(), strptime()
и некоторых
других. В число поддерживаемых ключевых слов входят abday
(сокращенные названия дней недели, начиная с воскресенья; элемент
соответствует спецификатору %a ), day (полные названия дней недели, %A ), abmon (сокращенные названия месяцев, %b ), mon
(полные названия
месяцев, %B ), d_t_fmt (принятое в данной %c ), d_fmt (принятое в данной среде
представление даты, %x ), t_fmt (принятое в данной среде
представление времени, %X ).
Особым образом устроен элемент era, определяющий способ
отсчета и отображения лет для каждой эры, поддерживаемой
направление:смещение:начальная_дата: конечная_дата:имя_эры:формат_эры
Здесь направление – знак плюс или минус, смещение – ближайший
к начальной дате номер года, начальная_дата – цепочка вида
гггг/мм/дд (год, месяц и число начала эры), конечная_дата – год,
месяц и число конца эры либо цепочки "-*" (конечной датой служит
начало отсчета времени) или "+*" (конечной датой служит конец отсчета
времени), формат_эры – цепочка, используемая при форматировании
номеров года в эре.
Отметим, что точка отсчета может быть как самой ранней, так и самой поздней в эре. Примерами служат две христианские эры – после и до Рождества Христова, соответственно.
В листинге 13.4 показано определение категории LC_TIME для
LC_TIME # POSIX-среда, категория LC_TIME # # Сокращенные названия дней недели (%a) abday "<S><u><n>";"<M><o><n>";"<T><u><e>";\ "<W><e><d>";"<T><h><u>";"<F><r><i>";"<S><a><t>" # # Полные названия дней недели (%A) day "<S><u><n><d><a><y>";\ "<M><o><n><d><a><y>";\ "<T><u><e><s><d><a><y>";\ "<W><e><d><n><e><s><d><a><y>";\ "<T><h><u><r><s><d><a><y>";\ "<F><r><i><d><a>\<y>";\ "<S><a><t><u><r><d><a><y>" # # Сокращенные названия месяцев (%b) abmon "<J><a><n>";"<F><e><b>";"<M><a><r>";\ "<A><p><r>";"<M><a><y>";"<J><u><n>";\ "<J><u><l>";"<A><u><g>";"<S><e><p>";\ "<O><c><t>";"<N><o><v>";"<D><e><c>" # # Полные названия месяцев (%B) mon "<J><a><n><u><a><r><y>"\ "<F><e><b><r><u><a><r><y>";\ "<M><a><r><c><h>";"<A><p><r><i><l>";\ "<M><a><y>";"<J><u><n><e>";\ "<J><u><l><y>";"<A><u><g><u><s><t>";\ "<S><e><p><t><e><m><b><e><r>";\ "<O><c><t><o><b><e><r>";\ "<N><o><v><e><m><b><e><r>";\ "<D><e><c><e><m><b><e><r>" # # Эквивалент AM/PM (%p) "AM";"PM" am_pm "<A><M>";"<P><M>" # # Принятое в POSIX-среде представление даты и времени (%c) # "%a %b %e %H:%M:%S %Y" d_t_fmt "<percent-sign><a><space><percent-sign>\ <b><space><percent-sign><e><space>\ <percent-sign><H><colon><percent-sign>\ <M><colon><percent-sign><S><space>\ <percent-sign><Y>" # # Принятое в POSIX-среде представление даты (%x) "%m/%d/%y" d_fmt "<percent-sign><m><slash><percent-sign><d>\ <slash><percent-sign><y>" # # Принятое в POSIX-среде представление времени (%X) "%H:%M:%S" t_fmt "<percent-sign><H><colon><percent-sign><M>\ <colon><percent-sign><S>" # # Принятое в POSIX-среде 12-часовое представление времени (%r) "%I:%M:%S %p" t_fmt_ampm "<percent-sign><I><colon><percent-sign\ <M><colon><percent-sign><S><space>\ <percent_sign><p>" # END LC_TIME
Категория LC_MESSAGES играет весьма ограниченную роль,
определяя положительные и отрицательные ответы. Соответственно, она
содержит два элемента – yesexpr и noexpr, значениями которых служат
LC_MESSAGES # POSIX-среда, категория LC_MESSAGES # yesexpr "<circumflex><left-square-bracket>\ <y><Y><right-square-bracket>" # noexpr "<circumflex><left-square-bracket>\ <n><N><right-square-bracket>" # END LC_MESSAGES
Для создания целевой localedef:
localedef [-c] [-f файл_отображения_символов]
[-i исходный_файл]
[-u имя_набора_символов]
имя_целевой_среды
Утилита localedef преобразует рассмотренное выше определение
категорий
Исходные данные для localedef поступают из файла с именем
операнда опции -i или со стандартного ввода.
Операнд имя_целевой_среды определяет имя создаваемой среды.
Она может быть как общедоступной, так и приватной, с ограниченным
доступом.
-f является -u можно задать имя нестандартного набора
символов.
Опция -c предписывает генерировать выходной файл даже при
наличии предупреждений.
Аргумент имя_целевой_среды идентифицирует созданную
языково-культурную среду. Если это имя начинается с символа /, оно
интерпретируется как localedef
стандартом не специфицируется); в противном случае
интерпретация имени зависит от реализации, а созданная среда становится
общедоступной.
Для получения информации о locale:
locale [-a | -m] locale [-ck] имя ...
Будучи вызванной без аргументов, утилита locale выдает на
стандартный вывод сводную информацию о среде, которая состоит из
значений соответствующих переменных окружения (описанных выше, а также
дополнительных, определенных, быть может, целевой системой).
Результат может выглядеть так, как показано в листинге 13.6. Кавычки вокруг
значений всех переменных окружения, кроме LANG, означают, что они не
были установлены явным образом, а определены по значению $LANG.
LANG=ru_RU.koi8r LC_CTYPE="ru_RU.koi8r" LC_NUMERIC="ru_RU.koi8r" LC_TIME="ru_RU.koi8r" LC_COLLATE="ru_RU.koi8r" LC_MONETARY="ru_RU.koi8r" LC_MESSAGES="ru_RU.koi8r" LC_PAPER="ru_RU.koi8r" LC_NAME="ru_RU.koi8r" LC_ADDRESS="ru_RU.koi8r" LC_TELEPHONE="ru_RU.koi8r" LC_MEASUREMENT="ru_RU.koi8r" LC_IDENTIFICATION="ru_RU.koi8r" LC_ALL=
При наличии аргументов выдается информация о некоторых (если задано ключевое слово) или обо всех (если указано имя категории) элементах категорий.
Опциям служебной программы locale приписан следующий
смысл.
-a
Выдать информацию обо всех общедоступных языково-культурных
средах (включая
-m
Выдать имена доступных файлов отображения символов.
-c
Выдавать имена выбранных (прямо или косвенно, посредством ключевых слов) категорий, что делает результаты более читабельными, когда они охватывают несколько категорий.
-k
Выдавать имена и значения заданных элементов категорий.
Операнд имя может быть именем категории, элемента категории
(ключевым словом) или зарезервированным словом . В двух
первых случаях выдается информация о поименованной категории или ее
элементе, в последнем – имя файла отображения символов, который был
использован при создании
Приведем еще два примера употребления утилиты locale. Данные
о категории LC_TIME, выдаваемые по команде
locale -ck LC_TIME
могут выглядеть так, как показано в листинге 13.7.
LC_TIME abday="Вск;Пнд;Втр;Срд;Чтв;Птн;Сбт" day="Воскресенье;Понедельник;Вторник;Среда; Четверг;Пятница;Суббота" abmon="Янв;Фев;Мар;Апр;Май;Июн;Июл;Авг;Сен; Окт;Ноя;Дек" mon="Января;Февраля;Марта;Апреля;Мая;Июня; Июля;Августа;Сентября;Октября;Ноября;Декабря" d_t_fmt="%a %d %b %Y %T" d_fmt="%d.%m.%Y" t_fmt="%T" . . . first_weekday=1 first_workday=1 cal_direction=1 date_fmt="%a %b %e %H:%M:%S %Z %Y" time-codeset="KOI8-R"
Второй пример демонстрирует фрагмент интернационализированного варианта shell-процедуры, анализирующей интерактивный ответ пользователя. Предполагается, что ответ является значением переменной response.
if echo "$response" | grep -Eq "$(locale yesexpr)" then echo "Ответ положительный" else echo "Ответ отрицательный" fi
Программная установка и опрос характеристик языково-культурной среды
Мы приступаем к рассмотрению функций, предназначенных для
работы с
Функция setlocale() (см. листинг 13.9) служит для установки
и/или опроса всей
#include <locale.h>
char *setlocale (int category,
const char *locale);
Аргумент category задает категорию ( LC_COLLATE, , LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME ), а если его
значение равно LC_ALL, то и всю среду.
Аргумент locale указывает на цепочку символов, содержащую
требуемые установки для выбранной категории (категорий); в общем случае
ее формат зависит от реализации. Имеется, однако, несколько
предопределенных, стандартизованных цепочек.
"POSIX" или "C"
Специфицирует минимальную языково-культурную среду
( setlocale() такая среда устанавливается по умолчанию при входе в main().
""
Специфицирует зависящую от реализации местную
языково-культурную среду, определяемую значениями переменных окружения LC_* и LANG. Интернационализированная программа должна выполнять вызов
вида
setlocale (LC_ALL, "");
для настройки на местную среду выполнения.
Если значением аргумента locale служит пустой указатель, функция setlocale() опрашивает текущее окружение и возвращает имя
используемой setlocale() для восстановления
соответствующей части
Разумеется, в случае неудачного завершения вызова setlocale()
результатом служит пустой указатель.
Получить детальную информацию о категориях LC_MONETARY и LC_NUMERIC текущей localeconv() (см. листинг 13.10).
#include <locale.h> struct lconv *localeconv (void);
Структура типа lconv была описана выше. Здесь мы отметим лишь
два момента.
Поля, имеющие тип char *, указывают на цепочки символов,
каждая из которых (за исключением *decimal_point ) может иметь вид ""
как признак того, что данное значение в текущей среде недоступно или
имеет нулевую длину.
Поля типа char содержат неотрицательные числа; CHAR_MAX
указывает на то, что данное значение в текущей среде недоступно.
Вызов localeconv() не может кончиться неудачей, однако
следует учитывать, что возвращаемая структура может быть
перезаписана последующими обращениями не только к localeconv(), но
и к setlocale().
Следующая программа (см. листинг 13.11) демонстрирует
использование функций setlocale() и localeconv().
#include <stdio.h>
#include <locale.h>
/* Функция опрашивает и выводит цепочки символов, */
/* ассоциированные с текущей средой и ее */
/* категориями */
void print_curr_locale_data (void) {
/* Массив категорий для setlocale() */
int ctgrs [] = {LC_ALL, LC_COLLATE, LC_CTYPE,
LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME};
/* Массив имен категорий */
char *ctgrnms [] = {"LC_ALL", "LC_COLLATE",
"LC_CTYPE", "LC_MESSAGES", "LC_MONETARY",
"LC_NUMERIC", "LC_TIME"};
unsigned int i;
printf ("Цепочки символов, ассоциированные в
текущей среде с\n");
for (i = 0; i < sizeof (ctgrs) / sizeof (int); i++) {
printf (" %s: %s\n", ctgrnms [i], setlocale
(ctgrs [i], NULL));
}
}
int main (void) {
struct lconv *plc;
/* Убедимся, что подразумеваемой является */
/* POSIX-среда */
printf ("Текущая языково-культурная среда:
подразумеваемая\n");
print_curr_locale_data();
/* Установим местную среду */
(void) setlocale (LC_ALL, "");
/* Опросим и выдадим ее характеристики */
printf ("Текущая языково-культурная среда:
местная\n");
print_curr_locale_data();
plc = localeconv ();
printf ("Некоторые элементы категорий
LC_MONETARY и LC_NUMERIC\n");
printf ("int_curr_symbol: %s\n",
plc->int_curr_symbol);
printf ("currency_symbol: %s\n",
plc->currency_symbol);
printf ("mon_decimal_point: %s\n",
plc->mon_decimal_point);
printf ("decimal_point: %s\n",
plc->decimal_point);
printf ("thousands_sep: %s\n",
plc->thousands_sep);
/* Сделаем "денежную" категорию украинской */
if (setlocale (LC_MONETARY, "ru_UA") == NULL) {
perror ("SETLOCALE");
return (1);
}
printf ("Категория LC_MONETARY переустановлена
для Украины\n");
print_curr_locale_data();
plc = localeconv ();
printf ("Некоторые элементы категории
LC_MONETARY\n");
printf ("int_curr_symbol: %s\n",
plc->int_curr_symbol);
printf ("currency_symbol: %s\n",
plc->currency_symbol);
return 0;
}
Возможный результат работы этой программы показан в листинге 13.12.
Текущая языково-культурная среда: подразумеваемая Цепочки символов, ассоциированные в текущей среде с LC_ALL: C LC_COLLATE: C LC_CTYPE: C LC_MESSAGES: C LC_MONETARY: C LC_NUMERIC: C LC_TIME: C Текущая языково-культурная среда: местная Цепочки символов, ассоциированные в текущей среде с LC_ALL: ru_RU.koi8r LC_COLLATE: ru_RU.koi8r LC_CTYPE: ru_RU.koi8r LC_MESSAGES: ru_RU.koi8r LC_MONETARY: ru_RU.koi8r LC_NUMERIC: ru_RU.koi8r LC_TIME: ru_RU.koi8r Некоторые элементы категорий LC_MONETARY и LC_NUMERIC int_curr_symbol: RUR currency_symbol: РУБ mon_decimal_point: . decimal_point: , thousands_sep: . Категория LC_MONETARY переустановлена для Украины Цепочки символов, ассоциированные в текущей среде с LC_ALL: LC_CTYPE=ru_RU.koi8r;LC_NUMERIC=ru_RU.koi8r; LC_TIME=ru_RU.koi8r;LC_COLLATE=ru_RU.koi8r; LC_MONETARY=ru_UA;LC_MESSAGES=ru_RU.koi8r; LC_PAPER=ru_RU.koi8r;LC_NAME=ru_RU.koi8r; LC_ADDRESS=ru_RU.koi8r;LC_TELEPHONE=ru_RU.koi8r; LC_MEASUREMENT=ru_RU.koi8r; LC_IDENTIFICATION=ru_RU.koi8r LC_COLLATE: ru_RU.koi8r LC_CTYPE: ru_RU.koi8r LC_MESSAGES: ru_RU.koi8r LC_MONETARY: ru_UA LC_NUMERIC: ru_RU.koi8r LC_TIME: ru_RU.koi8r Некоторые элементы категории LC_MONETARY int_curr_symbol: UAH currency_symbol: ГР
Для преобразования денежных величин в цепочку символов в
соответствии с настройками текущей strfmon() (см. листинг 13.13), входящей в
XSI-расширение стандарта POSIX-2001.
#include <monetary.h>
ssize_t strfmon (char *restrict s,
size_t maxsize,
const char *restrict format, ...);
Результат преобразования (длиной не более maxsize байт)
помещается в буфер, на который указывает аргумент s. Само преобразование
выполняется под управлением аргумента format. В формат могут входить
обычные символы, просто копируемые в выходную цепочку, а также
Обязательными являются только первый и последний компоненты. Возможных преобразований два:
i
Преобразовать значение типа double в денежную величину
международного формата.
n
Преобразовать значение типа double в денежную величину
местного формата.
В качестве результата функция strfmon() возвращает количество
байт, помещенное в массив s.
Может показаться, что в деле интернационализации/локализации
категориям LC_MONETARY и LC_NUMERIC повезло больше других,
поскольку для них определена многокомпонентная структура lconv, содержащая
значения всех ключевых слов этих категорий, и функция localeconv(),
позволяющая данную структуру получить. Однако на практике дело
обстоит прямо противоположным образом. Для других категорий настройка приложений
на местную языково-культурную среду сводится к вызову
setlocale (LC_ALL, "");
Всю остальную специфику среды учитывают функции isalpha(), tolower(), strcoll(), strftime() и т.д.,
которыми приложения
могут пользоваться стандартными способами.
В листинге 13.14 показан пример программы, использующей
упомянутые функции. Видно, как меняется их поведение при модификации
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <limits.h>
#include <monetary.h>
#define MY_VALUE 1234.567
int main (void) {
char sbuf [LINE_MAX];
printf ("Текущая языково-культурная среда:
подразумеваемая\n");
printf ("isalpha ('Б'): %d\n", isalpha ('Б'));
printf ("tolower ('Б'): '%c'\n", tolower ('Б'));
printf ("Результат преобразования в денежную
величину числа 1234.567\n");
if (strfmon (sbuf, sizeof (sbuf), "Международное
обозначение: %i\n", MY_VALUE) == -1) {
perror ("STRFMON");
return (1);
}
fputs (sbuf, stdout);
(void) strfmon (sbuf, sizeof (sbuf), "Местное
обозначение: %n\n", MY_VALUE);
fputs (sbuf, stdout);
(void) setlocale (LC_ALL, "");
printf ("Текущая языково-культурная среда: местная\n");
printf ("isalpha ('Б'): %d\n", isalpha ('Б'));
printf ("tolower ('Б'): '%c'\n", tolower ('Б'));
printf ("Результат преобразования в денежную
величину числа 1234.567\n");
(void) strfmon (sbuf, sizeof (sbuf),
"Международное обозначение: %i\n", MY_VALUE);
fputs (sbuf, stdout);
(void) strfmon (sbuf, sizeof (sbuf), "Местное
обозначение: %n\n", MY_VALUE);
fputs (sbuf, stdout);
(void) setlocale (LC_MONETARY, "ru_UA");
printf ("Категория LC_MONETARY переустановлена
для Украины\n");
printf ("Результат преобразования в денежную
величину числа 1234.567\n");
(void) strfmon (sbuf, sizeof (sbuf),
"Международное обозначение: %i\n", MY_VALUE);
fputs (sbuf, stdout);
(void) strfmon (sbuf, sizeof (sbuf), "Местное
обозначение: %n\n", MY_VALUE);
fputs (sbuf, stdout);
return 0;
}
Текущая
isalpha ('Б'): 0
tolower ('Б'): 'Б'
Результат преобразования в денежную величину
числа 1234.567
Международное обозначение: 1234.57
Местное обозначение: 1234.57
Текущая языково-культурная среда: местная
isalpha ('Б'): 1024
tolower ('Б'): 'б'
Результат преобразования в денежную величину
числа 1234.567
Международное обозначение: 1 234.57 RUR
Местное обозначение: 1 234.57 руб
Категория LC_MONETARY переустановлена для
Украины
Результат преобразования в денежную величину
числа 1234.567
Международное обозначение: 1 234.57 UAH
Местное обозначение: 1 234.57 ГР
Если требуется получить детальную информацию обо всех аспектах
nl_langinfo() (см. листинг 13.16), отнесенной стандартом
POSIX-2001 к расширению XSI.
#include <langinfo.h> char *nl_langinfo (nl_item item);
Аргументом функции nl_langinfo() могут служить именованные
константы, определенные в заголовочном файле <langinfo.h>.
В общем и целом они соответствуют описанным выше ключевым словам. В
качестве результата nl_langinfo() возвращает указатель на цепочку
символов, содержащую данные о выбранном элементе среды. Если в
текущей среде этот элемент отсутствует, выдаются данные для
Пример программы, использующей функцию nl_langinfo(),
показан в листинге 13.17, возможные результаты ее работы – в листинге 13.18.
#include <stdio.h>
#include <locale.h>
#include <langinfo.h>
#include <regex.h>
#include <limits.h>
int main (void) {
regex_t cere; /* Скомпилированные расширенные */
/* регулярные выражения */
regex_t ceren;
int reerrcode; /* Код ошибки от regcomp или */
/* regexec */
char reerrbuf [LINE_MAX]; /* Буфер для строк с */
/* сообщениями об ошибках */
char response [LINE_MAX]; /* Буфер для ответа */
/* пользователя */
printf ("Текущая языково-культурная среда:
подразумеваемая\n");
printf ("Элемент YESEXPR категории LC_MESSAGES:
%s\n", nl_langinfo (YESEXPR));
printf ("Элемент MON_1 категории LC_TIME: %s\n",
nl_langinfo (MON_1));
(void) setlocale (LC_ALL, "");
printf ("Текущая языково-культурная среда:
местная\n");
printf ("Элемент YESEXPR категории LC_MESSAGES:
%s\n", nl_langinfo (YESEXPR));
printf ("Элемент MON_1 категории LC_TIME: %s\n",
nl_langinfo (MON_1));
/* Скомпилируем расширенное регулярное */
/* выражение для утвердительного ответа */
if ((reerrcode = regcomp (cere, nl_langinfo
(YESEXPR), REG_EXTENDED | REG_ICASE |
REG_NOSUB )) != 0) {
(void) regerror (reerrcode, cere, reerrbuf,
sizeof (reerrbuf));
fputs (reerrbuf, stderr);
fputc ('\n', stderr);
regfree (cere);
return (reerrcode);
}
/* То же для отрицательного ответа */
if ((reerrcode = regcomp (ceren, nl_langinfo
(NOEXPR), REG_EXTENDED | REG_ICASE |
REG_NOSUB )) != 0) {
(void) regerror (reerrcode, ceren, reerrbuf,
sizeof (reerrbuf));
fputs (reerrbuf, stderr);
fputc ('\n', stderr);
regfree (ceren);
return (reerrcode);
}
fputs ("Вы поддерживаете идею стандартизации
программных интерфейсов? ", stdout);
fgets (response, sizeof (response), stdin);
if (regexec (cere, response, 0, NULL, 0) == 0) {
fputs ("Ответ положительный\n", stdout);
} else if (regexec (ceren, response, 0, NULL, 0) == 0) {
fputs ("Ответ отрицательный\n", stdout);
} else {
fputs ("Ответ уклончивый\n", stdout);
}
regfree (cere);
regfree (ceren);
return 0;
}
Текущая языково-культурная среда: подразумеваемая Элемент YESEXPR категории LC_MESSAGES: ^[yY] Элемент MON_1 категории LC_TIME: January Текущая языково-культурная среда: местная Элемент YESEXPR категории LC_MESSAGES: ^[ДдYy].* Элемент MON_1 категории LC_TIME: Января Вы поддерживаете идею стандартизации программных интерфейсов? Да Ответ положительный
К сожалению, обязательная часть стандарта POSIX-2001 содержит
лишь минимум средств для настройки на целевую среду выдаваемых strerror()
(см. листинг 13.19), которая отображает номера (коды) ошибок в
сообщения, зависящие от LC_MESSAGES.
#include <string.h> char *strerror (int errnum);
Обычно в качестве аргумента этой функции используют errno, но
номера ошибок могут поступать и из произвольного источника.
В листинге 13.20 показан пример программы, выдающей perror() и strerror().
#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <errno.h>
int main (void) {
fprintf (stderr, "Текущая языково-культурная
среда: подразумеваемая\n");
errno = 1;
perror ("PERROR, сообщение номер 1");
fprintf (stderr, "STRERROR, сообщение номер 1:
%s\n", strerror (1));
(void) setlocale (LC_ALL, "");
fprintf (stderr, "Текущая языково-культурная
среда: местная\n");
errno = 1;
perror ("PERROR, сообщение номер 1");
fprintf (stderr, "STRERROR, сообщение номер 1:
%s\n", strerror (1));
(void) setlocale (LC_MESSAGES, "ru_UA");
fprintf (stderr, "Категория LC_MESSAGES
переустановлена для Украины\n");
errno = 1;
perror ("PERROR, сообщение номер 1");
fprintf (stderr, "STRERROR, сообщение номер 1:
%s\n", strerror (1));
return 0;
}
Развитые средства для работы с
Стандарт не специфицирует формат каталогов сообщений, но
предлагает служебную программу gencat для их генерации по исходному
описанию:
gencat каталог файл_сообщений ...
Аргумент каталог задает
Исходное описание может состоять из нескольких файлов сообщений, строки которых, помимо прочих, содержат следующие директивы.
$set идентификатор_набора_сообщений комментарий
Задает [1, NL_SETMAX].
В пределах одного исходного файла сообщений идентификаторы должны
задаваться в порядке возрастания. Подразумеваемым является набор NL_SETD (см. <nl_types.h> ).
идентификатор_сообщения текст_сообщения
[1, NL_MSGMAX]. В пределах одного набора
идентификаторы сообщений задаются в порядке возрастания. Длина текста
сообщения должна лежать в диапазоне [0, NL_TEXTMAX].
Отметим, что генерируемые каталоги сообщений могут иметь двоичный формат и, следовательно, нуждаться в перегенерации при переносе на другие системы. Иными словами, и здесь (как и везде в стандарте POSIX) речь идет о мобильности на уровне исходных текстов.
В прикладной программе работа с каталогами сообщений
осуществляется посредством функций catopen(), catgets() и catclose()
(см. листинг 13.21).
#include <nl_types.h> nl_catd catopen (const char *name, int oflag); char *catgets (nl_catd catd, int set_id, int msg_id, const char *s); int catclose (nl_catd catd);
Функция catopen() открывает каталог сообщений и возвращает
его LANG (если аргумент oflag равен нулю) или LC_MESSAGES (если oflag
равен NL_CAT_LOCALE ).
К сожалению, рекомендации по расположению каталогов сообщений на момент написания данного текста еще не были выработаны. Стандарт POSIX-2001 ограничился замечанием о том, что авторам приложений следует соблюдать осторожность, дабы избежать конфликтов с другими приложениями и стандартными служебными программами.
catopen(), используется в
вызове catgets() для чтения сообщения под номером msg_id из набора с
номером set_id. Аргумент s указывает на подразумеваемую цепочку
символов, которая будет возвращена catgets() в качестве результата,
если запрошенное сообщение не удастся прочитать из каталога.
Функция catclose() закрывает каталог сообщений.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.