В настоящее время актуальный стандарт - это POSIX 2008 и его дополнение POSIX 1003.13 |
Языково-культурная среда
Может показаться, что в деле интернационализации/локализации категориям LC_MONETARY и LC_NUMERIC повезло больше других, поскольку для них определена многокомпонентная структура lconv, содержащая значения всех ключевых слов этих категорий, и функция localeconv(), позволяющая данную структуру получить. Однако на практике дело обстоит прямо противоположным образом. Для других категорий настройка приложений на местную языково-культурную среду сводится к вызову
setlocale (LC_ALL, "");
Всю остальную специфику среды учитывают функции isalpha(), tolower(), strcoll(), strftime() и т.д., которыми приложения могут пользоваться стандартными способами.
В листинге 13.14 показан пример программы, использующей упомянутые функции. Видно, как меняется их поведение при модификации языково-культурной среды (см. листинг 13.15).
#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; }13.14. Пример программы, работающей в нескольких языково-культурных средах.
Текущая языково-культурная среда: подразумеваемая
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 ГР13.15. Текущая языково-культурная среда: подразумеваемая
Если требуется получить детальную информацию обо всех аспектах языково-культурной среды, можно воспользоваться функцией nl_langinfo() (см. листинг 13.16), отнесенной стандартом POSIX-2001 к расширению XSI.
#include <langinfo.h> char *nl_langinfo (nl_item item);13.16. Описание функции nl_langinfo().
Аргументом функции nl_langinfo() могут служить именованные константы, определенные в заголовочном файле <langinfo.h>. В общем и целом они соответствуют описанным выше ключевым словам. В качестве результата nl_langinfo() возвращает указатель на цепочку символов, содержащую данные о выбранном элементе среды. Если в текущей среде этот элемент отсутствует, выдаются данные для POSIX-среды.
Пример программы, использующей функцию 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; }13.17. Пример программы, использующей функцию nl_langinfo().
Текущая языково-культурная среда: подразумеваемая Элемент YESEXPR категории LC_MESSAGES: ^[yY] Элемент MON_1 категории LC_TIME: January Текущая языково-культурная среда: местная Элемент YESEXPR категории LC_MESSAGES: ^[ДдYy].* Элемент MON_1 категории LC_TIME: Января Вы поддерживаете идею стандартизации программных интерфейсов? Да Ответ положительный13.18. Возможные результаты работы программы, использующей функцию nl_langinfo().
К сожалению, обязательная часть стандарта POSIX-2001 содержит лишь минимум средств для настройки на целевую среду выдаваемых диагностических сообщений. По сути он сводится к функции strerror() (см. листинг 13.19), которая отображает номера (коды) ошибок в сообщения, зависящие от языково-культурной среды, точнее, от установки категории LC_MESSAGES.
#include <string.h> char *strerror (int errnum);13.19. Описание функции strerror().
Обычно в качестве аргумента этой функции используют 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; }13.20. Пример программы, выдающей диагностические сообщения в разных языково-культурных средах и разными средствами.