zabieram się do nauki ncurses, bo chcę napisać program z takim interfejsem.
Wszystkie stringi w programie mają być kodowane w UTF-8. Czy
niemożliwe/trudne/łatwe jest aby użytkownikowi zawsze wyświetlało się to
dobrze?
bajcik
--
Krzysztof Garus
Stronka: http://kolos.math.uni.lodz.pl/~bajcik/
Serwis: http://gielda.linux.pl/ #GG 2065861
dodam że znalazłem fajny tekst związany z tym zagadnieniem:
http://groups.google.com/groups?hl=pl&lr=&selm=slrn8inpn5.fk.radecki%40localhost.localdomain
Ale pytanie o to jak zadbać o poprawność obsługi od strony programisty jest
aktualne.
bajcik
> zabieram się do nauki ncurses, bo chcę napisać program z takim
> interfejsem. Wszystkie stringi w programie mają być kodowane w
> UTF-8. Czy niemożliwe/trudne/łatwe jest aby użytkownikowi zawsze
> wyświetlało się to dobrze?
Są dwa warianty części API curses: wąski, używający typów chtype,
char * (np. addch, addstr, getch) i szeroki, z cchar_t, wchar_t *
(np. add_wch, add_wstr, get_wch).
ncurses z jednego źródła produkuje dwie biblioteki, używające
wewnętrznie wąskich i szerokich znaków (libcurses i libcursesw).
API z wąskimi znakami nadaje się tylko do kodowań, w których jeden
znak zajmuje jeden bajt. Biblioteka z wąskimi znakami obsługuje tylko
wąskie API.
API z szerokimi znakami nadaje się do dowolnych kodowań obsługiwanych
przez system, przy czym programista musi podawać ciągi wchar_t (jeden
cchar_t może zawierać kilka wchar_t, jeśli to jest znak z osobno
kodowanymi akcentami - API to przewiduje, ale nie wiem, jak działa
obecna implementacja). Biblioteka z szerokimi znakami obsługuje oba
API. Wewnętrznie konwertuje wszystko do wchar_t, a przy wyświetlaniu
konwertuje z powrotem.
Jeśli używamy libcursesw, to sensowniej jest używać tylko szerokiego
API. Jest pewne, że addch/getch nie ma sensu w UTF-8 i że addstr nie
zadziała w UTF-8 z libcurses. Nie wiem, jak się zachowa addstr w UTF-8
z libcursesw (i inne operacje na całych napisach), ale zgaduję, że źle.
Szerokie API to jedyny sposób na pełnoekranowe wyświetlanie się na
terminalach UTF-8. Teraz chyba większość X-owych terminali obsługuje
UTF-8 (np. GNOME Terminal).
Niestety szerokiego API z ncurses mało kto jeszcze używa (choć od
dawna jest wyspecyfikowane przez X/Open, więc zgaduję, że jakieś inne
implementacje curses niż ncurses na komercyjnych Uniksach to mogły
obsługiwać) i dopiero na początku października zostały w nim
poprawione grube błędy (add_wch ignorowało atrybuty znaku, get_wch źle
przekodowywało znak jeśli kodowanie było inne niż ISO-8859-1 i UTF-8).
Teraz już działa, przynajmniej to, co testowałem (napisałem Tetrisa).
Użycie szerokiego API z libcursesw działa na terminalach
w jednobajtowych kodowaniach i UTF-8. Kodowanie musi być zadeklarowane
z locale, żeby się poprawnie wyświetlało, natomiast samo API pracuje
na wchar_t, które pod Linuxem jest Unikodem (4 bajty na znak).
To jest wygodne zwłaszcza z poziomu języków, które wewnętrznie pracują
na Unikodzie.
Obecny maintainer ncurses, Thomas E. Dickey, szybko odpowiada na mejle
na liście ncurses.
--
__("< Marcin Kowalczyk
\__/ qrc...@knm.org.pl
^^ http://qrnik.knm.org.pl/~qrczak/
> Jeśli używamy libcursesw, to sensowniej jest używać tylko szerokiego
> API. Jest pewne, że addch/getch nie ma sensu w UTF-8 i że addstr nie
> zadziała w UTF-8 z libcurses. Nie wiem, jak się zachowa addstr w UTF-8
> z libcursesw (i inne operacje na całych napisach), ale zgaduję, że źle.
> Szerokie API to jedyny sposób na pełnoekranowe wyświetlanie się na
> terminalach UTF-8. Teraz chyba większość X-owych terminali obsługuje
> UTF-8 (np. GNOME Terminal).
Dzięki za wyjaśnienia. Tak sie zastanawiam: czy nie prościej byłoby uzywać
"zwykłej" libcurses i iconv'ować z/do UTF-8?
> Dzięki za wyjaśnienia. Tak sie zastanawiam: czy nie prościej byłoby uzywać
> "zwykłej" libcurses i iconv'ować z/do UTF-8?
To nie będzie działać w trybie UTF-8. libcurses przechowuje tylko
1 bajt na znak, nie będzie poprawnie odświeżać ekranu.
Co prawda lynx tak robił, ale w pokręcony i kruchy sposób. Ustawiał
szerokość ekranu na sztucznie dużo i pilnował, żeby ncurses odświeżał
za każdym razem całe linie (jeśli curses ma odświeżyć kawałek linii
zaczynając od jej połowy, to w złym miejscu umieści kursor).
co innego miałem na myśli: przed użyciem każdej z funkcji skonwertować napis w
utf-8 na lokalny (wskazany w konfiguracji przez użytkownika) i dalej po
staremu. libcurses nie będzie wiedziało o jakichśtam utf-8 wcześniej.
Oczywiście wszystkie znaczki nie będące w docelowym kodowaniu byłyby ucięte.
> co innego miałem na myśli: przed użyciem każdej z funkcji skonwertować
> napis w utf-8 na lokalny (wskazany w konfiguracji przez użytkownika)
> i dalej po staremu. libcurses nie będzie wiedziało o jakichśtam
> utf-8 wcześniej.
Jeśli lokalnym jest UTF-8, to program nie będzie się poprawnie wyświetlać,
a mógłby.