При попытке чтения символов сначала функцией getchar() а потом getwchar() (или наоборот - сначала getwchar() а потом getchar()) вторая функция возвращает EOF.
#include
#include
main (int ac, char *av[])
{
printf ("locale: %s
",setlocale(LC_ALL,""));
int c1 = 5, c2 = 6;
wint_t wc1 = 998, wc2 = 999;
int fd;
errno = 10000;
if (av[1]) {
printf ("getchar()...getwchar()
");
c1 = getchar();
c2 = getchar();
// freopen("/dev/tty","r",stdin);
// fd = dup(0);
// fclose(stdin);
// stdin = fdopen(dup2(fd,0),"r");
// clearerr(stdin);
// fflush(stdin);
wc1 = getwchar();
wc2 = getwchar();
} else {
printf ("getwchar()...getchar()
");
wc1 = getwchar();
wc2 = getwchar();
// freopen("/dev/tty","r",stdin);
// fd = dup(0);
// fclose(stdin);
// stdin = fdopen(dup2(fd,0),"r");
// clearerr(stdin);
// fflush(stdin);
c1 = getchar();
c2 = getchar();
}
printf ("errno = %d [%m]
",errno);
printf ("c1=%x c2=%x wc1=%x wc2=%x
",c1,c2,wc1,wc2);
}
avp@avp-xub11:~/src/ig/web-agent$ ./a.out
locale: ru_RU.UTF-8
getwchar()...getchar()
1234
errno = 29 [Недопустимая операция смещения]
c1=ffffffff c2=ffffffff wc1=31 wc2=32
avp@avp-xub11:~/src/ig/web-agent$
От наличия вызова setlocale() ситуация (принципиально) не меняется. Из всех придуманных мной попыток наладить переключение, удается только freopen(), но это не может быть нормальным решением проблемы, т.к. уже буферизованные данные пропадают.
В windows проблема не наблюдается, но там другая (однобайтная) локализация: locale: Russian_Russia.1251
Как решить данную задачу?
Ответ
Нашел кое-что не обнадеживающее в man fwide
if stream has no orientation yet; in this case the next
I/O operation might change the orientation (to byte oriented if it is a
char I/O operation, or to wide-character oriented if it is a wide-char‐
acter I/O operation).
Once a stream has an orientation, it cannot be changed and persists
until the stream is closed.
Похоже проблема просто (без хаков структур из libio.h (пока не очень понятно в какой момент, сорсы libc надо читать)) не решается.
Или сделать свои аналоги семейства getwchar() ??? Или аналоги под другим именем ?
Пока вопрос не закрываю, жду советов.
UPDATE
Читать libio стало лень, написал свое. Может кому-нибудь пригодится. Если остальной код интересен, могу выложить куда-нибудь.
/*
ucsutf.h avp 2012
Функции для UTF-8 и Unicode (ASCII&Cyrillic), независимые от setlocale()
*/
#ifndef UCSUTF_H
#define UCSUTF_H
#include
// возвращает ucs из utf-8 в памяти
extern int utf8_to_ucs (const char *utf, int *step, int *err);
// записать ucs в кодировке utf-8 в память, возвращает к-во записанных байт
extern int ucs_to_utf8 (int uc, char *b);
// аналоги ctype для ucs (ascii & cyrillic)
extern int isAlpha (int ucs);
extern int isLower (int ucs);
extern int isUpper (int ucs);
extern int toLower (int ucs);
extern int toUpper (int ucs);
// длина utf-8 символа (по первому байту)
extern int utf8_chrlen (const char *utf);
// convert символ utf-8 в памяти (по месту), возвращают к-во байт
extern int utf8_toUpper (char *s, int *err);
extern int utf8_toLower (char *s, int *err);
struct getucs {
u_int ucs, // m.b. EOF
nc, // прочитано из stream байт в bytes[]
err; // 0 if OK, при ошибке - err == nc
char bytes[8];
};
extern int utf8_fgetc (struct getucs *uc, FILE *stream); // ucs из utf-8 stream
#endif
/*
ucsutf.c avp 2012
Функции для UTF-8 и Unicode (ASCII&Cyrillic), независимые от setlocale()
*/
#include
#include "ucsutf.h"
/*
utf-8 схема error: 0xFF, 0xFE
1111 110x , 1111 10xx , 1111 0xxx , 1110 xxxx , 110x xxxx , 10xx xxxx
10xx xxxx , 10xx xxxx , 10xx xxxx , 10xx xxxx , 10xx xxxx
10xx xxxx , 10xx xxxx , 10xx xxxx , 10xx xxxx
10xx xxxx , 10xx xxxx , 10xx xxxx
10xx xxxx , 10xx xxxx
10xx xxxx
*/
// значимые биты из первого байта UTF-8
static int mask[5] = { 0x01, 0x03 ,0x07 ,0x0F ,0x1F};
/*
Некая замена fgetwc()
не зависит от setlocale() и ПОЗВОЛЯЕТ использовать fgetc() и др.
Возвращает UCS from stream UTF-8 characters or EOF
если преобразование UTF-8 -> UCS невозможно возвращает EOF
и устанавливает errno в EILSEQ
Также заполняет структуру getucs прочитанными байтами
*/
int
utf8_fgetc (struct getucs *uc, FILE *f)
{
uc->nc = uc->err = 0;
int c, n = 5;
if (feof(f))
c = EOF;
else if ((c = fgetc(f)) != EOF) {
uc->bytes[uc->nc++] = c;
if (c > 127) {
if ((c & 0xc0) == 0x80 || c == 0xff || c == 0xfe) {
c = EOF;
uc->err = 1;
} else {
while (n && (c & (1<
Комментариев нет:
Отправить комментарий