[[ Last modified: 2007-03-13 ]] This patch adds to ekg (tested with 1.7 RC 3) support for locales. (That is, you will be able to run ekg in an UTF-8 terminal.) Usage guide: 0. Install the `ncursesw' library. 1. Apply the patch. 2. ./configure --your-favourite-options 3. Fix `LDFLAGS' in `src/Makefile', so that to link with `ncursesw'. 4. Compile. 5. Make sure your locale (i.e. LC_CTYPE) is correct. 5. Run ekg, set the `display_pl_chars' to 2. 6. Delight if it works. diff -urN src.orig/commands.c src/commands.c --- src.orig/commands.c 2007-03-11 13:27:15.000000000 +0100 +++ src/commands.c 2007-03-13 12:18:54.000000000 +0100 @@ -537,7 +537,9 @@ strftime(buf1, sizeof(buf1), format_find((t->tm_yday == now_days) ? "show_status_ekg_started_today" : "show_status_ekg_started"), t); if (!sess || sess->state != GG_STATE_CONNECTED) { + disable_recode(); char *tmp = format_string(format_find("show_status_not_avail")); + enable_recode(); printq("show_status_status", tmp, ""); printq("show_status_ekg_started_since", buf1); @@ -555,6 +557,7 @@ return 0; } + disable_recode(); if (GG_S_F(config_status)) priv = format_string(format_find("show_status_private_on")); else @@ -564,6 +567,7 @@ r2 = xstrmid(config_reason, GG_STATUS_DESCR_MAXSIZE, -1); tmp = format_string(format_find(ekg_status_label(config_status, "show_status_")), r1, r2); + enable_recode(); xfree(r1); xfree(r2); @@ -830,7 +834,9 @@ s.id = pid; s.timeout = -1; if (add_commandline) { + disable_recode(); char *tmp = format_string(format_find("exec_prompt"), ((command[0] == '^') ? command + 1 : command)); + enable_recode(); s.buf = string_init(tmp); xfree(tmp); } else @@ -1511,14 +1517,19 @@ if (!strcasecmp(c->name, p) && !c->alias) { char *tmp = NULL; - if (strstr(c->brief_help, "%")) + if (strstr(c->brief_help, "%")) { + disable_recode(); tmp = format_string(c->brief_help); + enable_recode(); + } printq("help", c->name, c->params_help, tmp ? tmp : c->brief_help, ""); xfree(tmp); if (c->long_help && strcmp(c->long_help, "")) { + disable_recode(); char *foo, *tmp, *bar = format_string(c->long_help); + enable_recode(); foo = bar; @@ -1539,8 +1550,11 @@ if (xisalnum(*c->name) && !c->alias) { char *blah = NULL; - if (strstr(c->brief_help, "%")) + if (strstr(c->brief_help, "%")) { + disable_recode(); blah = format_string(c->brief_help); + enable_recode(); + } printq("help", c->name, c->params_help, blah ? blah : c->brief_help, ""); xfree(blah); @@ -1889,7 +1903,9 @@ if (!params_null && params[1]) return cmd_modify("list", params, NULL, quiet); + disable_recode(); status = format_string(format_find(ekg_status_label(u->status, "user_info_")), (u->first_name) ? u->first_name : u->display, u->descr); + enable_recode(); for (i = 0; i < strlen(status); i++) if (status[i] == 10) @@ -4723,6 +4739,7 @@ string_t list = string_init(NULL); list_t l; + disable_recode(); for (l = userlist; l; l = l->next) { struct userlist *u = l->data; const char *format = NULL; @@ -4756,6 +4773,7 @@ xfree(tmp); } + enable_recode(); if (strlen(list->str) > 0) print("quick_list", list->str); diff -urN src.orig/configfile.c src/configfile.c --- src.orig/configfile.c 2007-03-11 13:27:17.000000000 +0100 +++ src/configfile.c 2007-03-13 12:25:39.000000000 +0100 @@ -424,6 +424,7 @@ save_windows(); #endif + enable_recode(); for (l = variables; l; l = l->next) config_write_variable(f, l->data, base64); diff -urN src.orig/events.c src/events.c --- src.orig/events.c 2007-03-11 13:27:18.000000000 +0100 +++ src/events.c 2007-03-13 11:47:04.000000000 +0100 @@ -2669,6 +2669,7 @@ #define __format(x) ((count == 1 && !all) ? "search_results_single" x : "search_results_multi" x) + disable_recode(); switch (status & 0x7f) { case GG_STATUS_AVAIL: case GG_STATUS_AVAIL_DESCR: @@ -2687,6 +2688,7 @@ } gender = format_string(format_find(__format("_unknown")), ""); + enable_recode(); for (l = autofinds; l; l = l->next) { uin_t *d = l->data; diff -urN src.orig/stuff.c src/stuff.c --- src.orig/stuff.c 2007-03-11 13:27:19.000000000 +0100 +++ src/stuff.c 2007-03-13 11:43:02.000000000 +0100 @@ -1,13 +1,14 @@ /* $Id: stuff.c,v 1.448.2.3 2007/03/11 12:27:19 porridge Exp $ */ /* - * (C) Copyright 2001-2005 Wojtek Kaniewski + * (C) Copyright 2001-2006 Wojtek Kaniewski * Robert J. Wo¼ny * Pawe³ Maziarz * Dawid Jarosz * Piotr Domagalski * Piotr Kupisiewicz * Adam Wysocki + * Jakub Wilk * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as @@ -37,6 +38,7 @@ #endif #include +#include #include #include #ifdef HAVE_LIBGEN_H @@ -52,6 +54,8 @@ #include #include +#include + #include "commands.h" #include "compat.h" #include "dynstuff.h" @@ -1951,18 +1955,15 @@ */ void cp_to_iso(unsigned char *buf) { + static char conv_table[0x40] = "\x45\x81\x2c\x66\x22\x2e\x2b\x2b\x88\x3f\xa9\x3c\xa6\xab\xae\xac\x90\x60\x27\x22\x22\x2a\x2d\x2d\x98\x3f\xb9\x3e\xb6\xbb\xbe\xbc\xa0\xb7\xa2\xa3\xa4\xa1\x7c\xa7\xa8\x63\xaa\x3c\x7e\xad\x52\xaf\xb0\x3f\xb2\xb3\xb4\x75\x50\x2e\xb8\xb1\xba\x3e\xa5\xbd\xb5\xbf"; if (!buf) return; while (*buf) { - if (*buf == (unsigned char)'¥') *buf = '¡'; - if (*buf == (unsigned char)'¹') *buf = '±'; - if (*buf == 140) *buf = '¦'; - if (*buf == 156) *buf = '¶'; - if (*buf == 143) *buf = '¬'; - if (*buf == 159) *buf = '¼'; + if (*buf >= 0x80 && *buf < 0xc0) + *buf = conv_table[*buf - 0x80]; - if (*buf != 13 && *buf != 10 && (*buf < 32 || (*buf > 127 && *buf < 160))) + if (*buf != 13 && *buf != 10 && *buf < 32) *buf = '?'; buf++; @@ -1978,20 +1979,70 @@ */ void iso_to_cp(unsigned char *buf) { + static char conv_table[0x20] = "\xa0\xa5\xa2\xa3\xa4\xbc\x8c\xa7\xa8\x8a\xaa\x8d\x8f\xad\x8e\xaf\xb0\xb9\xb2\xb3\xb4\xbe\x9c\xa1\xb8\x9a\xba\x9d\x9f\xbd\x9e\xbf"; if (!buf) return; while (*buf) { - if (*buf == (unsigned char)'¡') *buf = '¥'; - if (*buf == (unsigned char)'±') *buf = '¹'; - if (*buf == (unsigned char)'¦') *buf = 'Œ'; - if (*buf == (unsigned char)'¶') *buf = 'œ'; - if (*buf == (unsigned char)'¬') *buf = ''; - if (*buf == (unsigned char)'¼') *buf = 'Ÿ'; + if (*buf >= 0x80 && *buf < 0xa0) + *buf = '?'; + else if (*buf >= 0xa0 && *buf < 0xc0) + *buf = conv_table[*buf - 0xa0]; buf++; } } +static char iso88592_asciimap[0x60] = " A~L*LSS\"SSTZ-ZZoa,l'ls^,sstz\"zzRAAAALCCCEEEEIIDDNNOOOOxRUUUUYTsraaaalccceeeeiiddnnoooo:ruuuuyt."; +static wchar_t iso88592_unimap[0x60] = { 0x00a0, 0x0104, 0x02d8, 0x0141, 0x00a4, 0x013d, 0x015a, 0x00a7, 0x00a8, 0x0160, 0x015e, 0x0164, 0x0179, 0x00ad, 0x017d, 0x017b, 0x00b0, 0x0105, 0x02db, 0x0142, 0x00b4, 0x013e, 0x015b, 0x02c7, 0x00b8, 0x0161, 0x015f, 0x0165, 0x017a, 0x02dd, 0x017e, 0x017c, 0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, 0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e, 0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, 0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df, 0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, 0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f, 0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, 0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9 }; + + +int localech_to_isoch(wint_t ch) +{ + int i; + if (ch < 0) + return -2; + if (ch < 0xa0) + return ch; + for (i = 0; i < 0x60; i++) + if (ch == iso88592_unimap[i]) + return i + 0xa0; + return -2; +} + +wchar_t *iso_to_wcs(unsigned char *buf) +{ + if (!buf) + return NULL; + int i; + size_t widebufsize = 1 + strlen(buf); + wchar_t *widebuf = xcalloc(sizeof(wchar_t), widebufsize); + for (i = 0; i < widebufsize; i++) + widebuf[i] = buf[i] < 0xa0 ? buf[i] : iso88592_unimap[buf[i] - 0xa0]; + if (wcstombs(NULL, widebuf, 0) == -1) + for (i = 0; i < widebufsize; i++) + widebuf[i] = buf[i] < 0xa0 ? buf[i] : iso88592_asciimap[buf[i] - 0xa0]; + return widebuf; +} + +unsigned char *iso_to_locale(unsigned char *buf) +{ + if (!buf) + return NULL; + wchar_t *wcs = iso_to_wcs(buf); + size_t bufsize = 1 + wcstombs(NULL, wcs, 0); + char *newbuf; + if (bufsize == 0) + newbuf = xstrdup("?"); + else + { + newbuf = xmalloc(bufsize); + wcstombs(newbuf, wcs, bufsize); + } + xfree(wcs); + return newbuf; +} + + /* * iso_to_ascii() * @@ -2003,28 +2054,11 @@ { if (!buf) return; - while (*buf) { - if (*buf == (unsigned char)'±') *buf = 'a'; - if (*buf == (unsigned char)'ê') *buf = 'e'; - if (*buf == (unsigned char)'æ') *buf = 'c'; - if (*buf == (unsigned char)'³') *buf = 'l'; - if (*buf == (unsigned char)'ñ') *buf = 'n'; - if (*buf == (unsigned char)'ó') *buf = 'o'; - if (*buf == (unsigned char)'¶') *buf = 's'; - if (*buf == (unsigned char)'¿') *buf = 'z'; - if (*buf == (unsigned char)'¼') *buf = 'z'; - - if (*buf == (unsigned char)'¡') *buf = 'A'; - if (*buf == (unsigned char)'Ê') *buf = 'E'; - if (*buf == (unsigned char)'Æ') *buf = 'C'; - if (*buf == (unsigned char)'£') *buf = 'L'; - if (*buf == (unsigned char)'Ñ') *buf = 'N'; - if (*buf == (unsigned char)'Ó') *buf = 'O'; - if (*buf == (unsigned char)'¦') *buf = 'S'; - if (*buf == (unsigned char)'¯') *buf = 'Z'; - if (*buf == (unsigned char)'¬') *buf = 'Z'; - + if (*buf >= 0x80 && *buf < 0xa0) + *buf = '?'; + else if (*buf >= 0xa0) + *buf = iso88592_asciimap[*buf - 0xa0]; buf++; } } diff -urN src.orig/stuff.h src/stuff.h --- src.orig/stuff.h 2007-03-11 13:27:20.000000000 +0100 +++ src/stuff.h 2007-03-13 11:52:18.000000000 +0100 @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -261,6 +262,8 @@ int config_display_daychanges; int config_display_notify; int config_display_pl_chars; +#define disable_recode() do { config_display_pl_chars |= 0x100; } while (0) +#define enable_recode() do { config_display_pl_chars &= ~0x100; } while (0) int config_display_sent; #if defined HAVE_LIBJPEG || defined HAVE_LIBUNGIF int config_display_token; @@ -441,6 +444,8 @@ void cp_to_iso(unsigned char *buf); void iso_to_cp(unsigned char *buf); void iso_to_ascii(unsigned char *buf); +unsigned char *iso_to_locale(unsigned char* buf); +int localech_to_isoch(wint_t ch); char *strip_chars(char *line, unsigned char what); char *strip_spaces(char *line); diff -urN src.orig/themes.c src/themes.c --- src.orig/themes.c 2007-03-13 11:38:56.000000000 +0100 +++ src/themes.c 2007-03-13 11:42:08.000000000 +0100 @@ -368,8 +368,16 @@ if (!dont_resolve && no_prompt_cache) theme_cache_reset(); - if (!config_display_pl_chars) + char *str; + switch (config_display_pl_chars) { + case 0: iso_to_ascii(buf->str); + break; + case 2: + str = iso_to_locale(buf->str); + string_free(buf, 0); + return str; + } return string_free(buf, 0); } diff -urN src.orig/ui-ncurses.c src/ui-ncurses.c --- src.orig/ui-ncurses.c 2007-03-11 13:27:21.000000000 +0100 +++ src/ui-ncurses.c 2007-03-13 11:50:13.000000000 +0100 @@ -6,6 +6,7 @@ * Pawe³ Maziarz * Piotr Kupisiewicz * Adam Wysocki + * Jakub Wilk * * Aspell support added by Piotr 'Deletek' Kupisiewicz * @@ -65,6 +66,8 @@ #include #include +#include + #include "commands.h" #include "libgadu.h" #include "mail.h" @@ -788,25 +791,29 @@ w->start = 0; for (y = 0; y < height && w->start + y < w->lines_count; y++) { + int x0 = 0; + int attr0 = A_NORMAL; struct screen_line *l = &w->lines[w->start + y]; - + unsigned char *ch = NULL; wattrset(w->window, A_NORMAL); - for (x = 0; l->ts && x < l->ts_len; x++) - mvwaddch(w->window, top + y, left + x, (unsigned char) l->ts[x]); + if (l->ts) + mvwaddnstr(w->window, top + y, left, l->ts, l->ts_len); + else + mvwaddnstr(w->window, top + y, left, "", 0); + for (x = 0; x < l->prompt_len + l->len; x++) { int attr = A_NORMAL; - unsigned char ch, chattr; + unsigned chattr; if (x < l->prompt_len) { if (!l->prompt_str) continue; - - ch = l->prompt_str[x]; + ch = l->prompt_str + x; chattr = l->prompt_attr[x]; } else { - ch = l->str[x - l->prompt_len]; + ch = l->str + x - l->prompt_len; chattr = l->attr[x - l->prompt_len]; } @@ -816,24 +823,31 @@ if (!(chattr & 128)) attr |= color_pair(chattr & 7, 0, COLOR_BLACK); - if (ch == 10) { - ch = '|'; + if (*ch == 10) { + *ch = '|'; attr |= color_pair(COLOR_BLACK, 1, COLOR_BLACK); } - if (ch < 32) { - ch += 64; + if (*ch < 32) { + *ch += 64; attr |= A_REVERSE; } - if (ch > 127 && ch < 160) { - ch = '?'; + if (config_display_pl_chars == 1 && *ch > 127 && *ch < 160) { + *ch = '?'; attr |= A_REVERSE; } - wattrset(w->window, attr); - mvwaddch(w->window, top + y, left + x + l->ts_len, ch); + if (attr != attr0 || x == l->prompt_len-1) + { + waddnstr(w->window, (char*) ch - x + x0, x - x0); + x0 = x; + attr0 = attr; + wattrset(w->window, attr); + } } + if (ch) + waddnstr(w->window, (char*) ch - x + x0 + 1, x - x0); } w->redraw = 0; @@ -1734,9 +1748,15 @@ const char *p; struct format_data *data = data_; - if (!config_display_pl_chars) { + switch (config_display_pl_chars) + { + case 0: format = xstrdup(format); iso_to_ascii(format); + break; + case 2: + format = iso_to_locale((unsigned char*) format); + break; } p = format; @@ -1761,7 +1781,7 @@ int i, nest; if (*p != '%') { - waddch(w, (unsigned char) *p); + waddnstr(w, (unsigned char*) p, 1); p++; x++; continue; @@ -1841,29 +1861,35 @@ if (!strncmp(p, data[i].name, len) && p[len] == '}') { char *text = data[i].text; int j; - - if (!config_display_pl_chars) { + + switch (config_display_pl_chars) + { + case 0: text = xstrdup(text); iso_to_ascii(text); + break; + case 2: + text = iso_to_locale((unsigned char*) text); + break; } - for (j = 0; text && j < strlen(text); j++) { - if (text[j] != 10) { - waddch(w, (unsigned char) text[j]); - continue; - } - + for (j = 0; ; ) { + int k; + for (k = j; text[k] && text[k] != 10; k++); + waddnstr(w, text + j, k - j); + if (!text[k]) + break; wattrset(w, color_pair(COLOR_BLACK, 1, bgcolor)); waddch(w, '|'); wattrset(w, color_pair(fgcolor, bold, bgcolor)); + j = k + 1; } p += len; - x += strlen(data[i].text); + x += strlen(data[i].text); /* FIXME! */ - if (!config_display_pl_chars) + if (config_display_pl_chars != 1) xfree(text); - goto next; } } @@ -1916,7 +1942,7 @@ config_display_color = backup_display_color; - if (!config_display_pl_chars) + if (format != format_) xfree(format); return x - orig_x; @@ -2237,7 +2263,8 @@ ui_beep = ui_ncurses_beep; ui_event = ui_ncurses_event; ui_deinit = ui_ncurses_deinit; - + + setlocale(LC_ALL, ""); initscr(); cbreak(); noecho(); @@ -3269,7 +3296,16 @@ wattrset(w, A_REVERSE); } - mvwaddch(w, y, x, ch); + if (config_display_pl_chars == 2) + { + char buf[2], *str; + buf[0] = ch; + buf[1] = 0; + str = iso_to_locale(buf); + mvwaddstr(w, y, x, str); + } + else + mvwaddch(w, y, x, ch); wattrset(w, A_NORMAL); } @@ -3311,7 +3347,15 @@ { int ch; - ch = wgetch(input); + switch (wget_wch(input, &ch)) { + case KEY_CODE_YES: + break; + case ERR: + ch = -1; + break; + case OK: + ch = localech_to_isoch(ch); + } #ifdef WITH_PYTHON PYTHON_HANDLE_HEADER(keypress, "(ii)", meta, ch) diff -urN src.orig/userlist.c src/userlist.c --- src.orig/userlist.c 2007-03-11 13:27:23.000000000 +0100 +++ src/userlist.c 2007-03-13 11:56:58.000000000 +0100 @@ -813,6 +813,7 @@ struct userlist *u = userlist_find(uin, NULL); static char buf[100], *tmp; + disable_recode(); if (!u || !u->display) { if (uin == config_uin && config_nick && *config_nick) tmp = format_string(format_find("known_user"), config_nick, itoa(uin)); @@ -820,6 +821,7 @@ tmp = format_string(format_find("unknown_user"), itoa(uin)); } else tmp = format_string(format_find("known_user"), u->display, itoa(uin)); + enable_recode(); strlcpy(buf, tmp, sizeof(buf)); diff -urN src.orig/vars.c src/vars.c --- src.orig/vars.c 2007-03-11 13:27:23.000000000 +0100 +++ src/vars.c 2007-03-13 11:51:15.000000000 +0100 @@ -205,7 +205,7 @@ variable_add("display_daychanges", "dD", VAR_BOOL, 2, NULL, NULL, NULL, NULL); #endif variable_add("display_notify", "dn", VAR_MAP, 1, &config_display_notify, NULL, variable_map(4, 0, 0, "none", 1, 2, "all", 2, 1, "significant", 4, 0, "unknown"), NULL); - variable_add("display_pl_chars", "dp", VAR_BOOL, 1, &config_display_pl_chars, NULL, NULL, NULL); + variable_add("display_pl_chars", "dp", VAR_INT, 1, &config_display_pl_chars, NULL, variable_map(3, 0, 0, "no", 1, 2, "iso2", 2, 1, "locale"), NULL); variable_add("display_sent", "ds", VAR_BOOL, 1, &config_display_sent, NULL, NULL, NULL); #if defined HAVE_LIBJPEG || defined HAVE_LIBUNGIF variable_add("display_token", "dT", VAR_BOOL, 1, &config_display_token, NULL, NULL, NULL);