Como determinar a codificação de caracteres que um terminal usa em um programa C / C ++?

2

Eu notei que o SyncTERM usa uma codificação de caracteres diferente do emulador de terminal padrão do MacOS, e eles são incompatíveis entre si. Por exemplo, digamos que você queira imprimir um caractere de bloco em uma string de formato. No SyncTERM, que usa a codificação de caracteres IBM Extended ASCII, você usaria uma sequência de escape octal como 1 . No Terminal.app (e provavelmente iTerm2 também), isso apenas imprime um ponto de interrogação. Como esses terminais usam UTF-8, você precisa usar a sequência de escape \uxxxx .

Então, digamos que você queira imprimir um caractere não ASCII em uma string de formato, e você quer que ele funcione em todos os emuladores de terminal, independentemente do conjunto de caracteres. Eu estou supondo que você usaria uma entrada no banco de dados terminfo, mas eu não estou realmente familiarizado com o terminfo. Eu preciso de alguns ponteiros aqui.

    
por user628544 12.11.2016 / 19:00

3 respostas

3

Curto:

  • o terminfo não o levará até lá, não ajudará
  • não há uma maneira confiável de determinar qual codificação um terminal realmente usa
  • a partir de literais Unicode é o caminho a seguir, desde que você saiba qual codificação deseja usar no terminal
  • o usuário precisa saber qual localidade é apropriada e qual codificação o terminal pode fazer
  • o padrão C tem funções para converter caracteres "largos" que você terá disponível em qualquer plataforma semelhante a Unix (veja por exemplo setlocale , wcrtomb e wcsrtombs )
por 12.11.2016 / 20:21
2

Inicialize a localidade do seu aplicativo com setlocale(LC_ALL, "") e, em seguida, chame nl_langinfo(CODESET) . Isso fornece o valor resolvido das variáveis de ambiente LANG, LC_CTYPE, LC_ALL.

Isso não diz a você como o emulador de terminal realmente funciona, mas é nisso que praticamente todo aplicativo se baseia. Se isso der um resultado incorreto, o sistema está configurado incorretamente e quase todos os outros aplicativos também funcionarão incorretamente no emulador de terminal. Como desenvolvedor de aplicativos, não é seu trabalho tentar detectar e corrigir se ele está quebrado. Você pode seguramente assumir que está configurado corretamente para você. Como um desenvolvedor ou administrador de sysadmin ou de distribuição, o seu trabalho é garantir que as variáveis de localidade e o comportamento real do emulador de terminal correspondam.

    
por 13.11.2016 / 13:34
0

Se o emulador de terminal for bem projetado e configurado apropriadamente, ele garantirá que o valor da variável de ambiente LC_CTYPE seja definido para um valor consistente com sua codificação. Infelizmente, na prática, a verificação de LC_CTYPE nem sempre é confiável: pode ser incorreta ou incorreta. (Outras variáveis de ambiente podem transmitir as configurações de localidade, consulte para mais detalhes.

Se você tem alguma ideia de quais codificações de caracteres são prováveis, você pode determinar a codificação via heurística. Exibe uma cadeia de bytes que tem uma largura diferente em diferentes codificações e descobre quanto ela movimenta o cursor. Isso não ajudará em todos os casos, por exemplo, não é possível distinguir entre codificações de byte único. Mas se para você as únicas duas possibilidades prováveis são UTF-8 e uma codificação legada, isso funciona bem. Na minha inicialização do shell, defino LC_CTYPE dessa maneira, usando um script widthof que postei em Obtenha a largura de exibição de uma string de caracteres . widthof -1 exibe uma cadeia de 4 bytes que representa 2 caracteres em UTF-8 e na qual apenas 3 bytes são caracteres latino-N imprimíveis. Assim, uma largura de 2 significa UTF-8 (ou alguma outra codificação multibyte, o que não é provável para mim), uma largura de 3 significa latin-N (sem nenhuma maneira de saber N) e 4 significa alguma codificação de byte único com caracteres imprimíveis no intervalo de 128 a 159.

widthof -1
case $? in
  0) export LC_CTYPE=C;; # 7-bit charset
  2) locale_search .utf8 .UTF-8;; # utf8
  3) locale_search .iso88591 .ISO8859-1 .latin1 '';; # 8-bit with nonprintable 128-159, we assume latin1
  4) locale_search .iso88591 .ISO8859-1 .latin1 '';; # some full 8-bit charset, we assume latin1
  *) export LC_CTYPE=C;; # weird charset
esac
    
por 28.05.2018 / 22:47