Страницы

Поиск по вопросам

суббота, 6 октября 2018 г.

Можно ли переключаться между getchar() и getwchar()?

При попытке чтения символов сначала функцией getchar() а потом getwchar() (или наоборот - сначала getwchar() а потом getchar()) вторая функция возвращает EOF.
#include #include #include #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 #include #include #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< u_int ucs = c & mask[n-1]; n = 6-n; while (n--) { if ((c = fgetc(f)) == EOF) break; if (((uc->bytes[uc->nc++] = c) & 0xc0) != 0x80) { uc->err = uc->nc; c = EOF; break; } ucs <<= 6; ucs |= (c & 0x3f); } if (c != EOF) c = ucs; } } } if (uc->err) errno = EILSEQ; return uc->ucs = c; } .... ....

Комментариев нет:

Отправить комментарий