Страницы

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

воскресенье, 1 декабря 2019 г.

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

#c #linux


При попытке чтения символов сначала функцией getchar() а потом getwchar() (или наоборот
- сначала getwchar() а потом getchar()) вторая функция возвращает EOF.

#include 
#include 
#include 
#include 

#include 

main (int ac, char *av[])
{
  printf ("locale: %s\n",setlocale(LC_ALL,""));

  int    c1 = 5, c2 = 6;
  wint_t wc1 = 998, wc2 = 999;
  int fd;

  errno = 10000;
  if (av[1]) {
    printf ("getchar()...getwchar()\n");
    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()\n");
    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]\n",errno);
  printf ("c1=%x c2=%x wc1=%x wc2=%x\n",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

Как решить данную задачу?
    


Ответы

Ответ 1



Нашел кое-что не обнадеживающее в 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<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; } .... ....

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

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