diff --git a/README.md b/README.md index 239ea03..c53e156 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # mc +Midnight Commander is a visual shell much like a file manager, only with way more features. +It is text mode, but also includes mouse support if you are running GPM. +Its coolest feature is the ability to ftp, view tar, zip files, and poke into RPMs for specific files. + diff --git a/mc-4.6.2-utf8.patch b/mc-4.6.2-utf8.patch new file mode 100644 index 0000000..66472af --- /dev/null +++ b/mc-4.6.2-utf8.patch @@ -0,0 +1,7017 @@ +diff --git a/acinclude.m4 b/acinclude.m4 +index f4c0e3b..f7f4fd4 100644 +--- a/acinclude.m4 ++++ b/acinclude.m4 +@@ -399,14 +399,14 @@ AC_DEFUN([MC_WITH_SLANG], [ + fi + + dnl Unless external S-Lang was requested, reject S-Lang with UTF-8 hacks +- if test x$with_screen = xslang; then +- : +- m4_if([$1], strict, , +- [AC_CHECK_LIB([slang], [SLsmg_write_nwchars], +- [AC_MSG_WARN([Rejecting S-Lang with UTF-8 support, \ +-it's not fully supported yet]) +- with_screen=mcslang])]) +- fi ++dnl if test x$with_screen = xslang; then ++dnl : ++dnl m4_if([$1], strict, , ++dnl [AC_CHECK_LIB([slang], [SLsmg_write_nwchars], ++dnl [AC_MSG_WARN([Rejecting S-Lang with UTF-8 support, \ ++dnl it's not fully supported yet]) ++dnl with_screen=mcslang])]) ++dnl fi + + if test x$with_screen = xslang; then + AC_DEFINE(HAVE_SYSTEM_SLANG, 1, +diff --git a/edit/edit-widget.h b/edit/edit-widget.h +index ab55764..fd51aaa 100644 +--- a/edit/edit-widget.h ++++ b/edit/edit-widget.h +@@ -30,6 +30,11 @@ typedef struct edit_key_map_type { + long command; + } edit_key_map_type; + ++struct action { ++ mc_wchar_t ch; ++ long flags; ++}; ++ + struct WEdit { + Widget widget; + +@@ -42,8 +47,17 @@ struct WEdit { + /* dynamic buffers and cursor position for editor: */ + long curs1; /* position of the cursor from the beginning of the file. */ + long curs2; /* position from the end of the file */ ++#ifndef UTF8 + unsigned char *buffers1[MAXBUFF + 1]; /* all data up to curs1 */ + unsigned char *buffers2[MAXBUFF + 1]; /* all data from end of file down to curs2 */ ++#else /* UTF8 */ ++ mc_wchar_t *buffers1[MAXBUFF + 1]; /* all data up to curs1 */ ++ mc_wchar_t *buffers2[MAXBUFF + 1]; /* all data from end of file down to curs2 */ ++ ++ unsigned char charbuf[MB_LEN_MAX]; ++ int charpoint; ++#endif /* UTF8 */ ++ + + /* search variables */ + long search_start; /* First character to start searching from */ +@@ -87,7 +101,7 @@ struct WEdit { + + /* undo stack and pointers */ + unsigned long stack_pointer; +- long *undo_stack; ++ struct action *undo_stack; + unsigned long stack_size; + unsigned long stack_size_mask; + unsigned long stack_bottom; +diff --git a/edit/edit.c b/edit/edit.c +index bec84d7..8df473b 100644 +--- a/edit/edit.c ++++ b/edit/edit.c +@@ -105,7 +105,11 @@ char *option_backup_ext = NULL; + + static void user_menu (WEdit *edit); + ++#ifndef UTF8 + int edit_get_byte (WEdit * edit, long byte_index) ++#else ++mc_wchar_t edit_get_byte (WEdit * edit, long byte_index) ++#endif + { + unsigned long p; + if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0) +@@ -134,7 +138,7 @@ edit_init_buffers (WEdit *edit) + + edit->curs1 = 0; + edit->curs2 = 0; +- edit->buffers2[0] = g_malloc (EDIT_BUF_SIZE); ++ edit->buffers2[0] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + } + + /* +@@ -159,7 +163,7 @@ edit_load_file_fast (WEdit *edit, const char *filename) + } + + if (!edit->buffers2[buf2]) +- edit->buffers2[buf2] = g_malloc (EDIT_BUF_SIZE); ++ edit->buffers2[buf2] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + + mc_read (file, + (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - +@@ -169,7 +173,7 @@ edit_load_file_fast (WEdit *edit, const char *filename) + for (buf = buf2 - 1; buf >= 0; buf--) { + /* edit->buffers2[0] is already allocated */ + if (!edit->buffers2[buf]) +- edit->buffers2[buf] = g_malloc (EDIT_BUF_SIZE); ++ edit->buffers2[buf] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + mc_read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE); + } + +@@ -242,9 +246,44 @@ edit_insert_stream (WEdit * edit, FILE * f) + { + int c; + long i = 0; +- while ((c = fgetc (f)) >= 0) { ++#ifndef UTF8 ++ while ((c = fgetc (f)) != EOF) { + edit_insert (edit, c); + i++; ++#else /* UTF8 */ ++ unsigned char buf[MB_LEN_MAX]; ++ int charpos = 0; ++ mbstate_t mbs; ++ ++ while ((c = fgetc (f)) != EOF) { ++ mc_wchar_t wc; ++ int size; ++ int j; ++ ++ buf[charpos++] = c; ++ ++ memset (&mbs, 0, sizeof (mbs)); ++ size = mbrtowc(&wc, (char *)buf, charpos, &mbs); ++ ++ if (size == -2) ++ continue; /* incomplete */ ++ ++ else if (size >= 0) { ++ edit_insert (edit, wc); ++ i++; ++ charpos = 0; ++ continue; ++ } ++ else { ++ ++ /* invalid */ ++#ifdef __STDC_ISO_10646__ ++ for (j=0; jlast_byte; i++) + if (fputc (edit_get_byte (edit, i), f) < 0) + break; ++#else /* UTF8 */ ++ for (i = 0; i < edit->last_byte; i++) { ++ mc_wchar_t wc = edit_get_byte (edit, i); ++ int res; ++ char tmpbuf[MB_LEN_MAX]; ++ mbstate_t mbs; ++ ++ memset (&mbs, 0, sizeof (mbs)); ++ ++#ifdef __STDC_ISO_10646__ ++ if (wc >= BINARY_CHAR_OFFSET && wc < (BINARY_CHAR_OFFSET + 256)) { ++ res = 1; ++ tmpbuf[0] = (char) (wc - BINARY_CHAR_OFFSET); ++ } else ++#endif ++ res = wcrtomb(tmpbuf, wc, &mbs); ++ if (res > 0) { ++ if (fwrite(tmpbuf, res, 1, f) != 1) ++ break; ++ } ++ } ++#endif /* UTF8 */ + return i; + } + +@@ -293,12 +355,46 @@ edit_insert_file (WEdit *edit, const char *filename) + int i, file, blocklen; + long current = edit->curs1; + unsigned char *buf; ++#ifdef UTF8 ++ mbstate_t mbs; ++ int bufstart = 0; ++ ++ memset (&mbs, 0, sizeof (mbs)); ++#endif /* UTF8 */ + if ((file = mc_open (filename, O_RDONLY | O_BINARY)) == -1) + return 0; + buf = g_malloc (TEMP_BUF_LEN); ++#ifndef UTF8 + while ((blocklen = mc_read (file, (char *) buf, TEMP_BUF_LEN)) > 0) { + for (i = 0; i < blocklen; i++) + edit_insert (edit, buf[i]); ++#else /* UTF8 */ ++ while ((blocklen = mc_read (file, (char *) buf + bufstart, TEMP_BUF_LEN - bufstart)) > 0) { ++ blocklen += bufstart; ++ bufstart = 0; ++ for (i = 0; i < blocklen; ) { ++ mc_wchar_t wc; ++ int j; ++ int size = mbrtowc(&wc, (char *)buf + i, blocklen - i, &mbs); ++ if (size == -2) { /*incomplete char*/ ++ bufstart = blocklen - i; ++ memcpy(buf, buf+i, bufstart); ++ i = blocklen; ++ memset (&mbs, 0, sizeof (mbs)); ++ } ++ else if (size <= 0) { ++#ifdef __STDC_ISO_10646__ ++ edit_insert (edit, BINARY_CHAR_OFFSET + (mc_wchar_t)buf[i]); ++#endif ++ memset (&mbs, 0, sizeof (mbs)); ++ i++; /* skip broken char */ ++ } ++ else { ++ edit_insert (edit, wc); ++ i+=size; ++ } ++ } ++#endif /* UTF8 */ + } + edit_cursor_move (edit, current - edit->curs1); + g_free (buf); +@@ -388,7 +484,11 @@ cleanup: + static int + edit_load_file (WEdit *edit) + { ++#ifndef UTF8 + int fast_load = 1; ++#else /* UTF8 */ ++ int fast_load = 0; /* can't be used with multibyte characters */ ++#endif /* UTF8 */ + + /* Cannot do fast load if a filter is used */ + if (edit_find_filter (edit->filename) >= 0) +@@ -454,6 +554,7 @@ edit_load_position (WEdit *edit) + edit->prev_col = column; + edit_move_to_prev_col (edit, edit_bol (edit, edit->curs1)); + edit_move_display (edit, line - (edit->num_widget_lines / 2)); ++ edit->charpoint = 0; + } + + /* Save cursor position in the file */ +@@ -537,7 +638,7 @@ edit_init (WEdit *edit, int lines, int columns, const char *filename, + edit_set_filename (edit, filename); + edit->stack_size = START_STACK_SIZE; + edit->stack_size_mask = START_STACK_SIZE - 1; +- edit->undo_stack = g_malloc ((edit->stack_size + 10) * sizeof (long)); ++ edit->undo_stack = g_malloc ((edit->stack_size + 10) * sizeof (struct action)); + if (edit_load_file (edit)) { + /* edit_load_file already gives an error message */ + if (to_free) +@@ -692,14 +793,23 @@ void edit_push_action (WEdit * edit, long c,...) + { + unsigned long sp = edit->stack_pointer; + unsigned long spm1; +- long *t; ++ ++ struct action *t; ++ mc_wchar_t ch = 0; ++ ++ if (c == CHAR_INSERT || c == CHAR_INSERT_AHEAD) { ++ va_list ap; ++ va_start (ap, c); ++ ch = va_arg (ap, mc_wint_t); ++ va_end (ap); ++ } + + /* first enlarge the stack if necessary */ + if (sp > edit->stack_size - 10) { /* say */ + if (option_max_undo < 256) + option_max_undo = 256; + if (edit->stack_size < (unsigned long) option_max_undo) { +- t = g_realloc (edit->undo_stack, (edit->stack_size * 2 + 10) * sizeof (long)); ++ t = g_realloc (edit->undo_stack, (edit->stack_size * 2 + 10) * sizeof (struct action)); + if (t) { + edit->undo_stack = t; + edit->stack_size <<= 1; +@@ -714,7 +824,7 @@ void edit_push_action (WEdit * edit, long c,...) + #ifdef FAST_MOVE_CURSOR + if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS) { + va_list ap; +- edit->undo_stack[sp] = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT; ++ edit->undo_stack[sp].flags = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT; + edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask; + va_start (ap, c); + c = -(va_arg (ap, int)); +@@ -725,12 +835,14 @@ void edit_push_action (WEdit * edit, long c,...) + && spm1 != edit->stack_bottom + && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom) { + int d; +- if (edit->undo_stack[spm1] < 0) { +- d = edit->undo_stack[(sp - 2) & edit->stack_size_mask]; +- if (d == c) { +- if (edit->undo_stack[spm1] > -1000000000) { ++ mc_wchar_t d_ch; ++ if (edit->undo_stack[spm1].flags < 0) { ++ d = edit->undo_stack[(sp - 2) & edit->stack_size_mask].flags; ++ d_ch = edit->undo_stack[(sp - 2) & edit->stack_size_mask].ch; ++ if (d == c && d_ch == ch) { ++ if (edit->undo_stack[spm1].flags > -1000000000) { + if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */ +- edit->undo_stack[spm1]--; ++ edit->undo_stack[spm1].flags--; + return; + } + } +@@ -738,19 +850,20 @@ void edit_push_action (WEdit * edit, long c,...) + #ifndef NO_STACK_CURSMOVE_ANIHILATION + else if ((c == CURS_LEFT && d == CURS_RIGHT) + || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */ +- if (edit->undo_stack[spm1] == -2) ++ if (edit->undo_stack[spm1].flags == -2) + edit->stack_pointer = spm1; + else +- edit->undo_stack[spm1]++; ++ edit->undo_stack[spm1].flags++; + return; + } + #endif + } else { +- d = edit->undo_stack[spm1]; +- if (d == c) { ++ d = edit->undo_stack[spm1].flags; ++ d_ch = edit->undo_stack[spm1].ch; ++ if (d == c && d_ch == ch) { + if (c >= KEY_PRESS) + return; /* --> no need to push multiple do-nothings */ +- edit->undo_stack[sp] = -2; ++ edit->undo_stack[sp].flags = -2; + goto check_bottom; + } + #ifndef NO_STACK_CURSMOVE_ANIHILATION +@@ -762,7 +875,9 @@ void edit_push_action (WEdit * edit, long c,...) + #endif + } + } +- edit->undo_stack[sp] = c; ++ edit->undo_stack[sp].flags = c; ++ edit->undo_stack[sp].ch = ch; ++ + check_bottom: + + edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask; +@@ -775,10 +890,10 @@ void edit_push_action (WEdit * edit, long c,...) + (((unsigned long) c + 1) & edit->stack_size_mask) == edit->stack_bottom) + do { + edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask; +- } while (edit->undo_stack[edit->stack_bottom] < KEY_PRESS && edit->stack_bottom != edit->stack_pointer); ++ } while (edit->undo_stack[edit->stack_bottom].flags < KEY_PRESS && edit->stack_bottom != edit->stack_pointer); + + /*If a single key produced enough pushes to wrap all the way round then we would notice that the [stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */ +- if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom] < KEY_PRESS) ++ if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom].flags < KEY_PRESS) + edit->stack_bottom = edit->stack_pointer = 0; + } + +@@ -787,30 +902,30 @@ void edit_push_action (WEdit * edit, long c,...) + then the file should be as it was when he loaded up. Then set edit->modified to 0. + */ + static long +-pop_action (WEdit * edit) ++pop_action (WEdit * edit, struct action *c) + { +- long c; + unsigned long sp = edit->stack_pointer; + if (sp == edit->stack_bottom) { +- return STACK_BOTTOM; ++ c->flags = STACK_BOTTOM; ++ return c->flags; + } + sp = (sp - 1) & edit->stack_size_mask; +- if ((c = edit->undo_stack[sp]) >= 0) { +-/* edit->undo_stack[sp] = '@'; */ ++ *c = edit->undo_stack[sp]; ++ if (edit->undo_stack[sp].flags >= 0) { + edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask; +- return c; ++ return c->flags; + } + if (sp == edit->stack_bottom) { + return STACK_BOTTOM; + } +- c = edit->undo_stack[(sp - 1) & edit->stack_size_mask]; +- if (edit->undo_stack[sp] == -2) { +-/* edit->undo_stack[sp] = '@'; */ ++ *c = edit->undo_stack[(sp - 1) & edit->stack_size_mask]; ++ ++ if (edit->undo_stack[sp].flags == -2) { + edit->stack_pointer = sp; + } else +- edit->undo_stack[sp]++; ++ edit->undo_stack[sp].flags++; + +- return c; ++ return c->flags; + } + + /* is called whenever a modification is made by one of the four routines below */ +@@ -831,7 +946,7 @@ static inline void edit_modification (WEdit * edit) + */ + + void +-edit_insert (WEdit *edit, int c) ++edit_insert (WEdit *edit, mc_wchar_t c) + { + /* check if file has grown to large */ + if (edit->last_byte >= SIZE_LIMIT) +@@ -869,12 +984,11 @@ edit_insert (WEdit *edit, int c) + /* add a new buffer if we've reached the end of the last one */ + if (!(edit->curs1 & M_EDIT_BUF_SIZE)) + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = +- g_malloc (EDIT_BUF_SIZE); ++ g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + + /* perform the insertion */ +- edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit-> +- curs1 & M_EDIT_BUF_SIZE] +- = (unsigned char) c; ++ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] ++ [edit->curs1 & M_EDIT_BUF_SIZE] = c; + + /* update file length */ + edit->last_byte++; +@@ -885,7 +999,7 @@ edit_insert (WEdit *edit, int c) + + + /* same as edit_insert and move left */ +-void edit_insert_ahead (WEdit * edit, int c) ++void edit_insert_ahead (WEdit * edit, mc_wchar_t c) + { + if (edit->last_byte >= SIZE_LIMIT) + return; +@@ -908,7 +1022,7 @@ void edit_insert_ahead (WEdit * edit, int c) + edit->last_get_rule += (edit->last_get_rule >= edit->curs1); + + if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE)) +- edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE); ++ edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c; + + edit->last_byte++; +@@ -918,7 +1032,7 @@ void edit_insert_ahead (WEdit * edit, int c) + + int edit_delete (WEdit * edit) + { +- int p; ++ mc_wint_t p; + if (!edit->curs2) + return 0; + +@@ -942,7 +1056,7 @@ int edit_delete (WEdit * edit) + edit->total_lines--; + edit->force |= REDRAW_AFTER_CURSOR; + } +- edit_push_action (edit, p + 256); ++ edit_push_action (edit, CHAR_INSERT_AHEAD, p); + if (edit->curs1 < edit->start_display) { + edit->start_display--; + if (p == '\n') +@@ -956,7 +1070,7 @@ int edit_delete (WEdit * edit) + static int + edit_backspace (WEdit * edit) + { +- int p; ++ mc_wint_t p; + if (!edit->curs1) + return 0; + +@@ -980,7 +1094,7 @@ edit_backspace (WEdit * edit) + edit->total_lines--; + edit->force |= REDRAW_AFTER_CURSOR; + } +- edit_push_action (edit, p); ++ edit_push_action (edit, CHAR_INSERT, p); + + if (edit->curs1 < edit->start_display) { + edit->start_display--; +@@ -993,10 +1107,18 @@ edit_backspace (WEdit * edit) + + #ifdef FAST_MOVE_CURSOR + +-static void memqcpy (WEdit * edit, unsigned char *dest, unsigned char *src, int n) ++static void memqcpy (WEdit * edit, mc_wchar_t *dest, mc_wchar_t *src, int n) + { + unsigned long next; ++#ifndef UTF8 + while ((next = (unsigned long) memccpy (dest, src, '\n', n))) { ++#else /* UTF8 */ ++ while (n) { ++ next = 0; ++ while (next < n && src[next]!='\n') next++; ++ if (next < n) next++; ++ wmemcpy (dest, src, next) ++#endif /* UTF8 */ + edit->curs_line--; + next -= (unsigned long) dest; + n -= next; +@@ -1009,7 +1131,7 @@ int + edit_move_backward_lots (WEdit *edit, long increment) + { + int r, s, t; +- unsigned char *p; ++ mc_wchar_t *p; + + if (increment > edit->curs1) + increment = edit->curs1; +@@ -1049,7 +1171,7 @@ edit_move_backward_lots (WEdit *edit, long increment) + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p; + else + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = +- g_malloc (EDIT_BUF_SIZE); ++ g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + } else { + g_free (p); + } +@@ -1087,7 +1209,7 @@ edit_move_backward_lots (WEdit *edit, long increment) + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p; + else + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = +- g_malloc (EDIT_BUF_SIZE); ++ g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + } else { + g_free (p); + } +@@ -1120,7 +1242,7 @@ void edit_cursor_move (WEdit * edit, long increment) + + c = edit_get_byte (edit, edit->curs1 - 1); + if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE)) +- edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE); ++ edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c; + edit->curs2++; + c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 - 1) & M_EDIT_BUF_SIZE]; +@@ -1144,7 +1266,7 @@ void edit_cursor_move (WEdit * edit, long increment) + + c = edit_get_byte (edit, edit->curs1); + if (!(edit->curs1 & M_EDIT_BUF_SIZE)) +- edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE); ++ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = g_malloc (EDIT_BUF_SIZE * sizeof(mc_wchar_t)); + edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c; + edit->curs1++; + c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1]; +@@ -1249,7 +1371,7 @@ long edit_move_forward3 (WEdit * edit, long current, int cols, long upto) + q = edit->last_byte + 2; + + for (col = 0, p = current; p < q; p++) { +- int c; ++ mc_wchar_t c; + if (cols != -10) { + if (col == cols) + return p; +@@ -1267,7 +1389,7 @@ long edit_move_forward3 (WEdit * edit, long current, int cols, long upto) + } else if (c < 32 || c == 127) + col += 2; /* Caret notation for control characters */ + else +- col++; ++ col += wcwidth(c); + } + return col; + } +@@ -1400,12 +1522,16 @@ static int + is_blank (WEdit *edit, long offset) + { + long s, f; +- int c; ++ mc_wchar_t c; + s = edit_bol (edit, offset); + f = edit_eol (edit, offset) - 1; + while (s <= f) { + c = edit_get_byte (edit, s++); ++#ifndef UTF8 + if (!isspace (c)) ++#else ++ if (!iswspace (c)) ++#endif /* UTF8 */ + return 0; + } + return 1; +@@ -1660,6 +1786,7 @@ my_type_of (int c) + return 2; + return 0x80000000UL; + } ++#ifndef UTF8 + if (isupper (c)) + c = 'A'; + else if (islower (c)) +@@ -1670,6 +1797,18 @@ my_type_of (int c) + c = '0'; + else if (isspace (c)) + c = ' '; ++#else ++ if (iswupper (c)) ++ c = 'A'; ++ else if (iswlower (c)) ++ c = 'a'; ++ else if (iswalpha (c)) ++ c = 'a'; ++ else if (iswdigit (c)) ++ c = '0'; ++ else if (iswspace (c)) ++ c = ' '; ++#endif /* UTF8 */ + q = strchr (option_chars_move_whole_word, c); + if (!q) + return 0xFFFFFFFFUL; +@@ -1694,10 +1833,18 @@ edit_left_word_move (WEdit *edit, int s) + c2 = edit_get_byte (edit, edit->curs1); + if (!(my_type_of (c1) & my_type_of (c2))) + break; ++#ifndef UTF8 + if (isspace (c1) && !isspace (c2)) ++#else ++ if (iswspace (c1) && !iswspace (c2)) ++#endif /* UTF8 */ + break; + if (s) ++#ifndef UTF8 + if (!isspace (c1) && isspace (c2)) ++#else ++ if (!iswspace (c1) && iswspace (c2)) ++#endif /* UTF8 */ + break; + } + } +@@ -1720,10 +1867,18 @@ edit_right_word_move (WEdit *edit, int s) + c2 = edit_get_byte (edit, edit->curs1); + if (!(my_type_of (c1) & my_type_of (c2))) + break; ++#ifndef UTF8 + if (isspace (c1) && !isspace (c2)) ++#else ++ if (iswspace (c1) && !iswspace (c2)) ++#endif /* UTF8 */ + break; + if (s) ++#ifndef UTF8 + if (!isspace (c1) && isspace (c2)) ++#else ++ if (!iswspace (c1) && iswspace (c2)) ++#endif /* UTF8 */ + break; + } + } +@@ -1743,7 +1898,11 @@ static void edit_right_delete_word (WEdit * edit) + break; + c1 = edit_delete (edit); + c2 = edit_get_byte (edit, edit->curs1); ++#ifndef UTF8 + if ((isspace (c1) == 0) != (isspace (c2) == 0)) ++#else ++ if ((iswspace (c1) == 0) != (iswspace (c2) == 0)) ++#endif /* UTF8 */ + break; + if (!(my_type_of (c1) & my_type_of (c2))) + break; +@@ -1758,7 +1917,11 @@ static void edit_left_delete_word (WEdit * edit) + break; + c1 = edit_backspace (edit); + c2 = edit_get_byte (edit, edit->curs1 - 1); ++#ifndef UTF8 + if ((isspace (c1) == 0) != (isspace (c2) == 0)) ++#else ++ if ((iswspace (c1) == 0) != (iswspace (c2) == 0)) ++#endif /* UTF8 */ + break; + if (!(my_type_of (c1) & my_type_of (c2))) + break; +@@ -1772,13 +1935,13 @@ static void edit_left_delete_word (WEdit * edit) + static void + edit_do_undo (WEdit * edit) + { +- long ac; ++ struct action ac; + long count = 0; + + edit->stack_disable = 1; /* don't record undo's onto undo stack! */ + +- while ((ac = pop_action (edit)) < KEY_PRESS) { +- switch ((int) ac) { ++ while (pop_action (edit, &ac) < KEY_PRESS) { ++ switch ((int) ac.flags) { + case STACK_BOTTOM: + goto done_undo; + case CURS_RIGHT: +@@ -1799,31 +1962,33 @@ edit_do_undo (WEdit * edit) + case COLUMN_OFF: + column_highlighting = 0; + break; ++ case CHAR_INSERT: ++ edit_insert (edit, ac.ch); ++ break; ++ case CHAR_INSERT_AHEAD: ++ edit_insert_ahead (edit, ac.ch); ++ break; + } +- if (ac >= 256 && ac < 512) +- edit_insert_ahead (edit, ac - 256); +- if (ac >= 0 && ac < 256) +- edit_insert (edit, ac); + +- if (ac >= MARK_1 - 2 && ac < MARK_2 - 2) { +- edit->mark1 = ac - MARK_1; ++ if (ac.flags >= MARK_1 - 2 && ac.flags < MARK_2 - 2) { ++ edit->mark1 = ac.flags - MARK_1; + edit->column1 = edit_move_forward3 (edit, edit_bol (edit, edit->mark1), 0, edit->mark1); +- } else if (ac >= MARK_2 - 2 && ac < KEY_PRESS) { +- edit->mark2 = ac - MARK_2; ++ } else if (ac.flags >= MARK_2 - 2 && ac.flags < KEY_PRESS) { ++ edit->mark2 = ac.flags - MARK_2; + edit->column2 = edit_move_forward3 (edit, edit_bol (edit, edit->mark2), 0, edit->mark2); + } + if (count++) + edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */ + } + +- if (edit->start_display > ac - KEY_PRESS) { +- edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display); ++ if (edit->start_display > ac.flags - KEY_PRESS) { ++ edit->start_line -= edit_count_lines (edit, ac.flags - KEY_PRESS, edit->start_display); + edit->force |= REDRAW_PAGE; +- } else if (edit->start_display < ac - KEY_PRESS) { +- edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS); ++ } else if (edit->start_display < ac.flags - KEY_PRESS) { ++ edit->start_line += edit_count_lines (edit, edit->start_display, ac.flags - KEY_PRESS); + edit->force |= REDRAW_PAGE; + } +- edit->start_display = ac - KEY_PRESS; /* see push and pop above */ ++ edit->start_display = ac.flags - KEY_PRESS; /* see push and pop above */ + edit_update_curs_row (edit); + + done_undo:; +@@ -2103,7 +2268,7 @@ static void edit_goto_matching_bracket (WEdit *edit) + * passed as -1. Commands are executed, and char_for_insertion is + * inserted at the cursor. + */ +-void edit_execute_key_command (WEdit *edit, int command, int char_for_insertion) ++void edit_execute_key_command (WEdit *edit, int command, mc_wint_t char_for_insertion) + { + if (command == CK_Begin_Record_Macro) { + edit->macro_i = 0; +@@ -2138,7 +2303,7 @@ static const char * const shell_cmd[] = SHELL_COMMANDS_i; + all of them. It also does not check for the Undo command. + */ + void +-edit_execute_cmd (WEdit *edit, int command, int char_for_insertion) ++edit_execute_cmd (WEdit *edit, int command, mc_wint_t char_for_insertion) + { + edit->force |= REDRAW_LINE; + +@@ -2171,7 +2336,7 @@ edit_execute_cmd (WEdit *edit, int command, int char_for_insertion) + } + + /* An ordinary key press */ +- if (char_for_insertion >= 0) { ++ if (char_for_insertion != (mc_wint_t) -1) { + if (edit->overwrite) { + if (edit_get_byte (edit, edit->curs1) != '\n') + edit_delete (edit); +diff --git a/edit/edit.h b/edit/edit.h +index 4a1c39b..672bf3d 100644 +--- a/edit/edit.h ++++ b/edit/edit.h +@@ -25,6 +25,27 @@ + + #include + ++#include "src/tty.h" ++ ++#ifdef UTF8 ++#include ++#include ++ ++#define mc_wchar_t wchar_t ++#define mc_wint_t wint_t ++ ++#else ++ ++#define mc_wchar_t unsigned char ++#define mc_wint_t int ++ ++#endif ++ ++ ++/* unicode private use area */ ++#define BINARY_CHAR_OFFSET 0xFFE00 ++ ++ + #define N_menus 5 + + #define SEARCH_DIALOG_OPTION_NO_SCANF (1 << 0) +@@ -86,6 +107,8 @@ + #define START_STACK_SIZE 32 + + /* Some codes that may be pushed onto or returned from the undo stack */ ++#define CHAR_INSERT 65 ++#define CHAR_INSERT_AHEAD 66 + #define CURS_LEFT 601 + #define CURS_RIGHT 602 + #define DELCHAR 603 +@@ -105,7 +128,7 @@ + + struct macro { + short command; +- short ch; ++ mc_wchar_t ch; + }; + + struct WEdit; +@@ -120,8 +143,12 @@ void edit_reload_menu (void); + void menu_save_mode_cmd (void); + int edit_raw_key_query (const char *heading, const char *query, int cancel); + int edit_file (const char *_file, int line); +-int edit_translate_key (WEdit *edit, long x_key, int *cmd, int *ch); ++int edit_translate_key (WEdit *edit, long x_key, int *cmd, mc_wint_t *ch); ++#ifndef UTF8 + int edit_get_byte (WEdit * edit, long byte_index); ++#else /* UTF8 */ ++mc_wchar_t edit_get_byte (WEdit * edit, long byte_index); ++#endif /* UTF8 */ + int edit_count_lines (WEdit * edit, long current, int upto); + long edit_move_forward (WEdit * edit, long current, int lines, long upto); + long edit_move_forward3 (WEdit * edit, long current, int cols, long upto); +@@ -148,11 +175,11 @@ int edit_block_delete_cmd (WEdit * edit); + void edit_delete_line (WEdit * edit); + + int edit_delete (WEdit * edit); +-void edit_insert (WEdit * edit, int c); ++void edit_insert (WEdit * edit, mc_wchar_t c); + void edit_cursor_move (WEdit * edit, long increment); + void edit_push_action (WEdit * edit, long c, ...); + void edit_push_key_press (WEdit * edit); +-void edit_insert_ahead (WEdit * edit, int c); ++void edit_insert_ahead (WEdit * edit, mc_wchar_t c); + long edit_write_stream (WEdit * edit, FILE * f); + char *edit_get_write_filter (const char *writename, const char *filename); + int edit_save_confirm_cmd (WEdit * edit); +@@ -183,7 +210,7 @@ void edit_goto_cmd (WEdit * edit); + int eval_marks (WEdit * edit, long *start_mark, long *end_mark); + void edit_status (WEdit * edit); + void edit_execute_key_command (WEdit *edit, int command, +- int char_for_insertion); ++ mc_wint_t char_for_insertion); + void edit_update_screen (WEdit * edit); + int edit_print_string (WEdit * e, const char *s); + void edit_move_to_line (WEdit * e, long line); +@@ -233,7 +260,7 @@ void edit_mail_dialog (WEdit *edit); + void format_paragraph (WEdit *edit, int force); + + /* either command or char_for_insertion must be passed as -1 */ +-void edit_execute_cmd (WEdit *edit, int command, int char_for_insertion); ++void edit_execute_cmd (WEdit *edit, int command, mc_wint_t char_for_insertion); + + #define get_sys_error(s) (s) + +diff --git a/edit/editcmd.c b/edit/editcmd.c +index d223c35..b85d9cd 100644 +--- a/edit/editcmd.c ++++ b/edit/editcmd.c +@@ -60,7 +60,7 @@ + #include "../src/selcodepage.h" + + struct selection { +- unsigned char * text; ++ mc_wchar_t *text; + int len; + }; + +@@ -83,21 +83,16 @@ int edit_confirm_save = 1; + #define MAX_REPL_LEN 1024 + + static int edit_save_cmd (WEdit *edit); +-static unsigned char *edit_get_block (WEdit *edit, long start, ++static mc_wchar_t *edit_get_block (WEdit *edit, long start, + long finish, int *l); + +-static inline int my_lower_case (int c) ++static inline mc_wchar_t my_lower_case (mc_wchar_t c) + { ++#ifndef UTF8 + return tolower(c & 0xFF); +-} +- +-static const char * +-strcasechr (const char *s, int c) +-{ +- for (c = my_lower_case (c); my_lower_case ((int) *s) != c; ++s) +- if (*s == '\0') +- return 0; +- return s; ++#else ++ return towlower(c); ++#endif + } + + #ifndef HAVE_MEMMOVE +@@ -123,11 +118,11 @@ static void *memmove (void *dest, const void *src, size_t n) + #endif /* !HAVE_MEMMOVE */ + + /* #define itoa MY_itoa <---- this line is now in edit.h */ +-static char * ++static mc_wchar_t * + MY_itoa (int i) + { +- static char t[14]; +- char *s = t + 13; ++ static mc_wchar_t t[14]; ++ mc_wchar_t *s = t + 13; + int j = i; + *s-- = 0; + do { +@@ -212,6 +207,48 @@ void edit_refresh_cmd (WEdit * edit) + doupdate(); + } + ++#ifdef UTF8 ++ ++static size_t ++wchar_write(int fd, mc_wchar_t *buf, size_t len) ++{ ++ char *tmpbuf = g_malloc(len + MB_LEN_MAX); ++ mbstate_t mbs; ++ size_t i; ++ size_t outlen = 0; ++ size_t res; ++ ++ for (i = 0; i < len; i++) { ++ if (outlen >= len) { ++ if ((res = mc_write(fd, tmpbuf, outlen)) != outlen) { ++ g_free(tmpbuf); ++ return -1; ++ } ++ outlen = 0; ++ } ++ memset (&mbs, 0, sizeof (mbs)); ++#ifdef __STDC_ISO_10646__ ++ if (buf[i] >= BINARY_CHAR_OFFSET && buf[i] < (BINARY_CHAR_OFFSET + 256)) { ++ res = 1; ++ tmpbuf[outlen] = (char) (buf[i] - BINARY_CHAR_OFFSET); ++ ++ } else ++#endif ++ res = wcrtomb(tmpbuf + outlen, buf[i], &mbs); ++ if (res > 0) { ++ outlen += res; ++ } ++ } ++ if ((res = mc_write(fd, tmpbuf, outlen)) != outlen) { ++ g_free(tmpbuf); ++ return -1; ++ } ++ g_free(tmpbuf); ++ return len; ++} ++ ++#endif /* UTF8 */ ++ + /* If 0 (quick save) then a) create/truncate file, + b) save to ; + if 1 (safe save) then a) save to , +@@ -359,32 +396,48 @@ edit_save_file (WEdit *edit, const char *filename) + buf = 0; + filelen = edit->last_byte; + while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) { ++#ifndef UTF8 + if (mc_write (fd, (char *) edit->buffers1[buf], EDIT_BUF_SIZE) ++#else /* UTF8 */ ++ if (wchar_write (fd, edit->buffers1[buf], EDIT_BUF_SIZE) ++#endif /* UTF8 */ + != EDIT_BUF_SIZE) { + mc_close (fd); + goto error_save; + } + buf++; + } ++#ifndef UTF8 + if (mc_write + (fd, (char *) edit->buffers1[buf], ++#else /* UTF8 */ ++ if (wchar_write ++ (fd, edit->buffers1[buf], ++#endif /* UTF8 */ + edit->curs1 & M_EDIT_BUF_SIZE) != + (edit->curs1 & M_EDIT_BUF_SIZE)) { + filelen = -1; + } else if (edit->curs2) { + edit->curs2--; + buf = (edit->curs2 >> S_EDIT_BUF_SIZE); +- if (mc_write +- (fd, +- (char *) edit->buffers2[buf] + EDIT_BUF_SIZE - ++#ifndef UTF8 ++ if (mc_write(fd, (char *) edit->buffers2[buf] + EDIT_BUF_SIZE - ++#else /* UTF8 */ ++ if (wchar_write(fd, edit->buffers2[buf] + EDIT_BUF_SIZE - ++#endif /* UTF8 */ + (edit->curs2 & M_EDIT_BUF_SIZE) - 1, + 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) != + 1 + (edit->curs2 & M_EDIT_BUF_SIZE)) { + filelen = -1; + } else { + while (--buf >= 0) { ++#ifndef UTF8 + if (mc_write + (fd, (char *) edit->buffers2[buf], ++#else /* UTF8 */ ++ if (wchar_write ++ (fd, edit->buffers2[buf], ++#endif /* UTF8 */ + EDIT_BUF_SIZE) != EDIT_BUF_SIZE) { + filelen = -1; + break; +@@ -705,13 +758,21 @@ edit_delete_macro (WEdit * edit, int k) + if (!n || n == EOF) + break; + n = 0; ++#ifndef UTF8 + while (fscanf (f, "%hd %hd, ", ¯o[n].command, ¯o[n].ch)) ++#else /* UTF8 */ ++ while (fscanf (f, "%hd %lu, ", ¯o[n].command, ¯o[n].ch)) ++#endif /* UTF8 */ + n++; + fscanf (f, ";\n"); + if (s != k) { + fprintf (g, ("key '%d 0': "), s); + for (i = 0; i < n; i++) ++#ifndef UTF8 + fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch); ++#else /* UTF8 */ ++ fprintf (g, "%hd %lu, ", macro[i].command, macro[i].ch); ++#endif /* UTF8 */ + fprintf (g, ";\n"); + } + } +@@ -744,7 +805,11 @@ int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n) + if (f) { + fprintf (f, ("key '%d 0': "), s); + for (i = 0; i < n; i++) ++#ifndef UTF8 + fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch); ++#else /* UTF8 */ ++ fprintf (f, "%hd %lu, ", macro[i].command, macro[i].ch); ++#endif /* UTF8 */ + fprintf (f, ";\n"); + fclose (f); + if (saved_macros_loaded) { +@@ -794,10 +859,18 @@ int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k) + saved_macro[i++] = s; + if (!found) { + *n = 0; ++#ifndef UTF8 + while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", ¯o[*n].command, ¯o[*n].ch)) ++#else /* UTF8 */ ++ while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %lu, ", ¯o[*n].command, ¯o[*n].ch)) ++#endif /* UTF8 */ + (*n)++; + } else { ++#ifndef UTF8 + while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch)); ++#else /* UTF8 */ ++ while (2 == fscanf (f, "%hd %lu, ", &dummy.command, &dummy.ch)); ++#endif /* UTF8 */ + } + fscanf (f, ";\n"); + if (s == k) +@@ -945,7 +1018,7 @@ int eval_marks (WEdit * edit, long *start_mark, long *end_mark) + #define space_width 1 + + static void +-edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width) ++edit_insert_column_of_text (WEdit * edit, mc_wchar_t *data, int size, int width) + { + long cursor; + int i, col; +@@ -993,7 +1066,7 @@ edit_block_copy_cmd (WEdit *edit) + { + long start_mark, end_mark, current = edit->curs1; + int size; +- unsigned char *copy_buf; ++ mc_wchar_t *copy_buf; + + edit_update_curs_col (edit); + if (eval_marks (edit, &start_mark, &end_mark)) +@@ -1033,7 +1106,7 @@ edit_block_move_cmd (WEdit *edit) + { + long count; + long current; +- unsigned char *copy_buf; ++ mc_wchar_t *copy_buf; + long start_mark, end_mark; + int deleted = 0; + int x = 0; +@@ -1094,7 +1167,7 @@ edit_block_move_cmd (WEdit *edit) + edit_push_action (edit, COLUMN_ON); + column_highlighting = 0; + } else { +- copy_buf = g_malloc (end_mark - start_mark); ++ copy_buf = g_malloc ((end_mark - start_mark) * sizeof(mc_wchar_t)); + edit_cursor_move (edit, start_mark - edit->curs1); + edit_scroll_screen_over_cursor (edit); + count = start_mark; +@@ -1433,7 +1506,11 @@ static long sargs[NUM_REPL_ARGS][256 / sizeof (long)]; + /* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */ + /* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */ + static int ++#ifndef UTF8 + string_regexp_search (char *pattern, char *string, int match_type, ++#else /* UTF8 */ ++string_regexp_search (char *pattern, mc_wchar_t *wstring, int match_type, ++#endif /* UTF8 */ + int match_bol, int icase, int *found_len, void *d) + { + static regex_t r; +@@ -1442,6 +1519,11 @@ string_regexp_search (char *pattern, char *string, int match_type, + regmatch_t *pmatch; + static regmatch_t s[1]; + ++#ifdef UTF8 ++ char *string; ++ int i; ++#endif /* UTF8 */ ++ + pmatch = (regmatch_t *) d; + if (!pmatch) + pmatch = s; +@@ -1462,13 +1544,51 @@ string_regexp_search (char *pattern, char *string, int match_type, + old_type = match_type; + old_icase = icase; + } ++ ++#ifdef UTF8 ++ string = wchar_to_mbstr(wstring); ++ if (string == NULL) ++ return -1; ++#endif /* UTF8 */ ++ + if (regexec + (&r, string, d ? NUM_REPL_ARGS : 1, pmatch, + ((match_bol + || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) { + *found_len = 0; ++ ++#ifdef UTF8 ++ g_free(string); ++#endif /* UTF8 */ ++ + return -1; + } ++ ++#ifdef UTF8 ++ for (i = 0; i < (d ? NUM_REPL_ARGS : 1); i++) { ++ char tmp; ++ int new_o; ++ ++ if (pmatch[i].rm_so < 0) ++ continue; ++ tmp = string[pmatch[i].rm_so]; ++ string[pmatch[i].rm_so] = 0; ++ new_o = mbstrlen(string); ++ string[pmatch[i].rm_so] = tmp; ++ pmatch[i].rm_so = new_o; ++ ++ if (pmatch[i].rm_eo < 0) ++ continue; ++ tmp = string[pmatch[i].rm_eo]; ++ string[pmatch[i].rm_eo] = 0; ++ new_o = mbstrlen(string); ++ string[pmatch[i].rm_eo] = tmp; ++ pmatch[i].rm_eo = new_o; ++ } ++ ++ g_free(string); ++#endif /* UTF8 */ ++ + *found_len = pmatch[0].rm_eo - pmatch[0].rm_so; + return (pmatch[0].rm_so); + } +@@ -1476,13 +1596,29 @@ string_regexp_search (char *pattern, char *string, int match_type, + /* thanks to Liviu Daia for getting this + (and the above) routines to work properly - paul */ + ++#ifndef UTF8 + typedef int (*edit_getbyte_fn) (WEdit *, long); ++#else /* UTF8 */ ++typedef mc_wchar_t (*edit_getbyte_fn) (WEdit *, long); ++#endif /* UTF8 */ + + static long ++#ifndef UTF8 + edit_find_string (long start, unsigned char *exp, int *len, long last_byte, edit_getbyte_fn get_byte, void *data, int once_only, void *d) ++#else /* UTF8 */ ++edit_find_string (long start, unsigned char *exp_mb, int *len, long last_byte, edit_getbyte_fn get_byte, void *data, int once_only, void *d) ++#endif /* UTF8 */ + { + long p, q = 0; +- long l = strlen ((char *) exp), f = 0; ++ long f = 0; ++ ++#ifndef UTF8 ++ long l = strlen ((char *) exp); ++#else /* UTF8 */ ++ mc_wchar_t *exp = mbstr_to_wchar((char *)exp_mb); ++ mc_wchar_t *exp_backup = exp; ++ long l = wcslen(exp); ++#endif /* UTF8 */ + int n = 0; + + for (p = 0; p < l; p++) /* count conversions... */ +@@ -1491,19 +1627,22 @@ edit_find_string (long start, unsigned char *exp, int *len, long last_byte, edit + n++; + + if (replace_scanf || replace_regexp) { +- int c; +- unsigned char *buf; +- unsigned char mbuf[MAX_REPL_LEN * 2 + 3]; ++ mc_wint_t c; ++ mc_wchar_t *buf; ++ mc_wchar_t mbuf[MAX_REPL_LEN * 2 + 3]; + + replace_scanf = (!replace_regexp); /* can't have both */ + + buf = mbuf; + + if (replace_scanf) { +- unsigned char e[MAX_REPL_LEN]; +- if (n >= NUM_REPL_ARGS) +- return -3; +- ++ mc_wchar_t e[MAX_REPL_LEN]; ++ if (n >= NUM_REPL_ARGS) { ++#ifdef UTF8 ++ g_free(exp_backup); ++#endif /* UTF8 */ ++ return -3; ++ } + if (replace_case) { + for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) + buf[p - start] = (*get_byte) (data, p); +@@ -1517,20 +1656,36 @@ edit_find_string (long start, unsigned char *exp, int *len, long last_byte, edit + } + + buf[(q = p - start)] = 0; ++#ifndef UTF8 + strcpy ((char *) e, (char *) exp); + strcat ((char *) e, "%n"); ++#else /* UTF8 */ ++ wcscpy (e, exp); ++ wcscat (e, L"%n"); ++#endif /* UTF8 */ + exp = e; + + while (q) { + *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */ ++#ifndef UTF8 + if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) { ++#else /* UTF8 */ ++ if (n == swscanf (buf, exp, SCANF_ARGS)) { ++#endif /* UTF8 */ + if (*((int *) sargs[n])) { + *len = *((int *) sargs[n]); ++#ifdef UTF8 ++ g_free(exp_backup); ++#endif /* UTF8 */ + return start; + } + } +- if (once_only) ++ if (once_only) { ++#ifdef UTF8 ++ g_free(exp_backup); ++#endif /* UTF8 */ + return -2; ++ } + if (q + start < last_byte) { + if (replace_case) { + buf[q] = (*get_byte) (data, q + start); +@@ -1544,7 +1699,11 @@ edit_find_string (long start, unsigned char *exp, int *len, long last_byte, edit + start++; + buf++; /* move the window along */ + if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */ ++#ifndef UTF8 + memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */ ++#else /* UTF8 */ ++ wmemmove (mbuf, buf, (wcslen (buf) + 1)); /* reset it */ ++#endif /* UTF8 */ + buf = mbuf; + } + q--; +@@ -1571,10 +1730,16 @@ edit_find_string (long start, unsigned char *exp, int *len, long last_byte, edit + + buf = mbuf; + while (q) { ++#ifndef UTF8 + found_start = string_regexp_search ((char *) exp, (char *) buf, match_normal, match_bol, !replace_case, len, d); +- ++#else /* UTF8 */ ++ found_start = string_regexp_search ((char *) exp_mb, buf, match_normal, match_bol, !replace_case, len, d); ++#endif /* UTF8 */ + if (found_start <= -2) { /* regcomp/regexec error */ + *len = 0; ++#ifdef UTF8 ++ g_free (exp_backup); ++#endif /* UTF8 */ + return -3; + } + else if (found_start == -1) /* not found: try next line */ +@@ -1585,15 +1750,27 @@ edit_find_string (long start, unsigned char *exp, int *len, long last_byte, edit + match_bol = 0; + continue; + } +- else /* found */ ++ else { /* found */ ++#ifdef UTF8 ++ g_free(exp_backup); ++#endif /* UTF8 */ + return (start + offset - q + found_start); ++ } + } +- if (once_only) ++ if (once_only) { ++#ifdef UTF8 ++ g_free(exp_backup); ++#endif /* UTF8 */ + return -2; ++ } + + if (buf[q - 1] != '\n') { /* incomplete line: try to recover */ + buf = mbuf + MAX_REPL_LEN / 2; ++#ifndef UTF8 + q = strlen ((const char *) buf); ++#else /* UTF8 */ ++ q = wcslen (buf); ++#endif /* UTF8 */ + memmove (mbuf, buf, q); + p = start + q; + move_win = 1; +@@ -1603,36 +1780,59 @@ edit_find_string (long start, unsigned char *exp, int *len, long last_byte, edit + } + } + } else { ++#ifndef UTF8 + *len = strlen ((const char *) exp); ++#else /* UTF8 */ ++ *len = wcslen (exp); ++#endif /* UTF8 */ + if (replace_case) { + for (p = start; p <= last_byte - l; p++) { +- if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */ ++ if ((*get_byte) (data, p) == exp[0]) { /* check if first char matches */ + for (f = 0, q = 0; q < l && f < 1; q++) +- if ((*get_byte) (data, q + p) != (unsigned char)exp[q]) ++ if ((*get_byte) (data, q + p) != exp[q]) + f = 1; +- if (f == 0) ++ if (f == 0) { ++#ifdef UTF8 ++ g_free (exp_backup); ++#endif /* UTF8 */ + return p; ++ } + } +- if (once_only) ++ if (once_only) { ++#ifdef UTF8 ++ g_free(exp_backup); ++#endif /* UTF8 */ + return -2; ++ } + } + } else { + for (p = 0; exp[p] != 0; p++) + exp[p] = my_lower_case (exp[p]); + + for (p = start; p <= last_byte - l; p++) { +- if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) { ++ if (my_lower_case ((*get_byte) (data, p)) == exp[0]) { + for (f = 0, q = 0; q < l && f < 1; q++) +- if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q]) ++ if (my_lower_case ((*get_byte) (data, q + p)) != exp[q]) + f = 1; +- if (f == 0) ++ if (f == 0) { ++#ifdef UTF8 ++ g_free (exp_backup); ++#endif /* UTF8 */ + return p; ++ } + } +- if (once_only) ++ if (once_only) { ++#ifdef UTF8 ++ g_free (exp_backup); ++#endif /* UTF8 */ + return -2; ++ } + } + } + } ++#ifdef UTF8 ++ g_free (exp_backup); ++#endif /* UTF8 */ + return -2; + } + +@@ -1646,9 +1846,14 @@ edit_find_forwards (long search_start, unsigned char *exp, int *len, long last_b + + while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only, d)) >= 0) { + if (replace_whole) { ++#ifndef UTF8 + /*If the bordering chars are not in option_whole_chars_search then word is whole */ + if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1)) + && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len))) ++#else /* UTF8 */ ++ if (!iswalnum((*get_byte) (data, p - 1)) ++ && !iswalnum((*get_byte) (data, p + *len))) ++#endif /* UTF8 */ + return p; + if (once_only) + return -2; +@@ -1680,6 +1885,7 @@ edit_find (long search_start, unsigned char *exp, int *len, long last_byte, edit + + #define is_digit(x) ((x) >= '0' && (x) <= '9') + ++#ifndef UTF8 + #define snprint(v) { \ + *p1++ = *p++; \ + *p1 = '\0'; \ +@@ -1687,33 +1893,48 @@ edit_find (long search_start, unsigned char *exp, int *len, long last_byte, edit + if (n >= (size_t) (e - s)) goto nospc; \ + s += n; \ + } ++#else /* UTF8 */ ++#define snprint(v) { \ ++ *p1++ = *p++; \ ++ *p1 = '\0'; \ ++ n = swprintf(s, e-s, q1,v); \ ++ if (n >= (size_t) (e - s)) goto nospc; \ ++ s += n; \ ++ } ++#endif /* UTF8 */ + + /* this function uses the sprintf command to do a vprintf */ + /* it takes pointers to arguments instead of the arguments themselves */ + /* The return value is the number of bytes written excluding '\0' + if successfull, -1 if the resulting string would be too long and + -2 if the format string is errorneous. */ +-static int snprintf_p (char *str, size_t size, const char *fmt,...) +- __attribute__ ((format (printf, 3, 4))); +- +-static int snprintf_p (char *str, size_t size, const char *fmt,...) ++static int snprintf_p (mc_wchar_t *str, size_t size, const mc_wchar_t *fmt,...) + { + va_list ap; + size_t n; +- const char *q, *p; +- char *s = str, *e = str + size; +- char q1[40]; +- char *p1; ++ const mc_wchar_t *q, *p; ++ mc_wchar_t *s = str, *e = str + size; ++ mc_wchar_t q1[40]; ++ ++ mc_wchar_t *p1; + int nargs = 0; + + va_start (ap, fmt); + p = q = fmt; + ++#ifndef UTF8 + while ((p = strchr (p, '%'))) { ++#else /* UTF8 */ ++ while ((p = wcschr (p, L'%'))) { ++#endif /* UTF8 */ + n = p - q; + if (n >= (size_t) (e - s)) + goto nospc; ++#ifndef UTF8 + memcpy (s, q, n); /* copy stuff between format specifiers */ ++#else /* UTF8 */ ++ wmemcpy (s, q, n); /* copy stuff between format specifiers */ ++#endif /* UTF8 */ + s += n; + q = p; + p1 = q1; +@@ -1741,45 +1962,78 @@ static int snprintf_p (char *str, size_t size, const char *fmt,...) + *p1++ = *p++; + if (*p == '*') { + p++; ++#ifndef UTF8 + strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace field width with a number */ + p1 += strlen (p1); ++#else /* UTF8 */ ++ wcscpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace field width with a number */ ++ p1 += wcslen (p1); ++#endif /* UTF8 */ + } else { +- while (is_digit (*p) && p1 < q1 + 20) ++#ifndef UTF8 ++ while (is_digit (*p) ++#else /* UTF8 */ ++ while (iswdigit (*p) ++#endif /* UTF8 */ ++ && p1 < q1 + 20) + *p1++ = *p++; ++#ifndef UTF8 + if (is_digit (*p)) ++#else /* UTF8 */ ++ if (iswdigit (*p)) ++#endif /* UTF8 */ + goto err; + } + if (*p == '.') + *p1++ = *p++; + if (*p == '*') { + p++; ++#ifndef UTF8 + strcpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace precision with a number */ + p1 += strlen (p1); ++#else /* UTF8 */ ++ wcscpy (p1, MY_itoa (*va_arg (ap, int *))); /* replace precision with a number */ ++ p1 += wcslen (p1); ++#endif /* UTF8 */ + } else { +- while (is_digit (*p) && p1 < q1 + 32) ++#ifndef UTF8 ++ while (is_digit (*p) ++#else /* UTF8 */ ++ while (iswdigit (*p) ++#endif /* UTF8 */ ++ && p1 < q1 + 32) + *p1++ = *p++; ++#ifndef UTF8 + if (is_digit (*p)) ++#else /* UTF8 */ ++ if (iswdigit (*p)) ++#endif /* UTF8 */ + goto err; + } + /* flags done, now get argument */ + if (*p == 's') { ++#ifndef UTF8 + snprint (va_arg (ap, char *)); ++#else /* UTF8 */ ++ *p1++ = 'l'; ++ snprint (va_arg (ap, mc_wchar_t *)); ++#endif /* UTF8 */ + } else if (*p == 'h') { +- if (strchr ("diouxX", *p)) ++ if (*p < 128 && strchr ("diouxX", *p)) + snprint (*va_arg (ap, short *)); + } else if (*p == 'l') { + *p1++ = *p++; +- if (strchr ("diouxX", *p)) ++ if (*p < 128 && strchr ("diouxX", *p)) + snprint (*va_arg (ap, long *)); +- } else if (strchr ("cdiouxX", *p)) { ++ } else if (*p < 128 && strchr ("cdiouxX", *p)) { + snprint (*va_arg (ap, int *)); + } else if (*p == 'L') { + *p1++ = *p++; +- if (strchr ("EefgG", *p)) ++ if (*p < 128 && strchr ("EefgG", *p)) + snprint (*va_arg (ap, double *)); /* should be long double */ +- } else if (strchr ("EefgG", *p)) { ++ } else if (*p < 128 && strchr ("EefgG", *p)) { + snprint (*va_arg (ap, double *)); +- } else if (strchr ("DOU", *p)) { ++ } else if (*p < 128 && strchr ("DOU", *p)) { + snprint (*va_arg (ap, long *)); + } else if (*p == 'p') { + snprint (*va_arg (ap, void **)); +@@ -1788,10 +2042,17 @@ static int snprintf_p (char *str, size_t size, const char *fmt,...) + q = p; + } + va_end (ap); ++#ifndef UTF8 + n = strlen (q); + if (n >= (size_t) (e - s)) + return -1; + memcpy (s, q, n + 1); ++#else /* UTF8 */ ++ n = wcslen (q); ++ if (n >= (size_t) (e - s)) ++ return -1; ++ wmemcpy (s, q, n + 1); ++#endif /* UTF8 */ + return s + n - str; + nospc: + va_end (ap); +@@ -1970,8 +2231,11 @@ edit_replace_cmd (WEdit *edit, int again) + } + } + if (replace_yes) { /* delete then insert new */ ++#ifdef UTF8 ++ mc_wchar_t *winput2 = mbstr_to_wchar(input2); ++#endif /* UTF8 */ + if (replace_scanf) { +- char repl_str[MAX_REPL_LEN + 2]; ++ mc_wchar_t repl_str[MAX_REPL_LEN + 2]; + int ret = 0; + + /* we need to fill in sargs just like with scanf */ +@@ -1980,17 +2244,25 @@ edit_replace_cmd (WEdit *edit, int again) + for (k = 1; + k < NUM_REPL_ARGS && pmatch[k].rm_eo >= 0; + k++) { ++#ifndef UTF8 + unsigned char *t; ++#else /* UTF8 */ ++ mc_wchar_t *t; ++#endif + + if (pmatch[k].rm_eo - pmatch[k].rm_so > 255) { + ret = -1; + break; + } ++#ifndef UTF8 + t = (unsigned char *) &sargs[k - 1][0]; ++#else /* UTF8 */ ++ t = (mc_wchar_t *) &sargs[k - 1][0]; ++#endif /* UTF8 */ + for (j = 0; + j < pmatch[k].rm_eo - pmatch[k].rm_so + && j < 255; j++, t++) +- *t = (unsigned char) edit_get_byte (edit, ++ *t = edit_get_byte (edit, + edit-> + search_start + - +@@ -2008,14 +2280,23 @@ edit_replace_cmd (WEdit *edit, int again) + } + if (!ret) + ret = ++#ifndef UTF8 + snprintf_p (repl_str, MAX_REPL_LEN + 2, input2, ++#else /* UTF8 */ ++ snprintf_p (repl_str, MAX_REPL_LEN + 2, winput2, ++#endif /* UTF8 */ + PRINTF_ARGS); + if (ret >= 0) { + times_replaced++; + while (i--) + edit_delete (edit); ++#ifndef UTF8 + while (repl_str[++i]) + edit_insert (edit, repl_str[i]); ++#else /* UTF8 */ ++ while (winput2[++i]) ++ edit_insert (edit, winput2[i]); ++#endif /* UTF8 */ + } else { + edit_error_dialog (_(" Replace "), + ret == +@@ -2029,10 +2310,18 @@ edit_replace_cmd (WEdit *edit, int again) + times_replaced++; + while (i--) + edit_delete (edit); ++#ifndef UTF8 + while (input2[++i]) + edit_insert (edit, input2[i]); ++#else /* UTF8 */ ++ while (winput2[++i]) ++ edit_insert (edit, winput2[i]); ++#endif /* UTF8 */ + } + edit->found_len = i; ++#ifdef UTF8 ++ g_free (winput2); ++#endif /* UTF8 */ + } + /* so that we don't find the same string again */ + if (replace_backwards) { +@@ -2205,16 +2494,17 @@ edit_ok_to_exit (WEdit *edit) + #define TEMP_BUF_LEN 1024 + + /* Return a null terminated length of text. Result must be g_free'd */ +-static unsigned char * ++static mc_wchar_t * + edit_get_block (WEdit *edit, long start, long finish, int *l) + { +- unsigned char *s, *r; +- r = s = g_malloc (finish - start + 1); ++ mc_wchar_t *s, *r; ++ r = s = g_malloc ((finish - start + 1) * sizeof(mc_wchar_t)); + if (column_highlighting) { + *l = 0; + /* copy from buffer, excluding chars that are out of the column 'margins' */ + while (start < finish) { +- int c, x; ++ mc_wchar_t c; ++ int x; + x = edit_move_forward3 (edit, edit_bol (edit, start), 0, + start); + c = edit_get_byte (edit, start); +@@ -2247,11 +2537,15 @@ edit_save_block (WEdit * edit, const char *filename, long start, + return 0; + + if (column_highlighting) { +- unsigned char *block, *p; ++ mc_wchar_t *block, *p; + int r; + p = block = edit_get_block (edit, start, finish, &len); + while (len) { ++#ifndef UTF8 + r = mc_write (file, p, len); ++#else /* UTF8 */ ++ r = wchar_write (file, p, len); ++#endif /* UTF8 */ + if (r < 0) + break; + p += r; +@@ -2259,15 +2553,19 @@ edit_save_block (WEdit * edit, const char *filename, long start, + } + g_free (block); + } else { +- unsigned char *buf; ++ mc_wchar_t *buf; + int i = start, end; + len = finish - start; +- buf = g_malloc (TEMP_BUF_LEN); ++ buf = g_malloc (TEMP_BUF_LEN * sizeof(mc_wchar_t)); + while (start != finish) { + end = min (finish, start + TEMP_BUF_LEN); + for (; i < end; i++) + buf[i - start] = edit_get_byte (edit, i); ++#ifndef UTF8 + len -= mc_write (file, (char *) buf, end - start); ++#else /* UTF8 */ ++ len -= wchar_write (file, buf, end - start); ++#endif /* UTF8 */ + start = end; + } + g_free (buf); +@@ -2609,17 +2907,20 @@ edit_block_process_cmd (WEdit *edit, const char *shell_cmd, int block) + + /* prints at the cursor */ + /* returns the number of chars printed */ ++#ifndef UTF8 + int edit_print_string (WEdit * e, const char *s) ++#else /* UTF8 */ ++int edit_print_wstring (WEdit * e, mc_wchar_t *s) ++#endif /* UTF8 */ + { + int i = 0; + while (s[i]) +- edit_execute_cmd (e, -1, (unsigned char) s[i++]); ++ edit_execute_cmd (e, -1, s[i++]); + e->force |= REDRAW_COMPLETELY; + edit_update_screen (e); + return i; + } + +- + static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc) + { + FILE *p = 0; +@@ -2713,15 +3014,20 @@ void edit_mail_dialog (WEdit * edit) + /* find first character of current word */ + static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len) + { +- int i, c, last; ++ int i; ++ mc_wint_t c, last; + + /* return if at begin of file */ + if (edit->curs1 <= 0) + return 0; + +- c = (unsigned char) edit_get_byte (edit, edit->curs1 - 1); ++ c = edit_get_byte (edit, edit->curs1 - 1); + /* return if not at end or in word */ ++#ifndef UTF8 + if (isspace (c) || !(isalnum (c) || c == '_')) ++#else /* UTF8 */ ++ if (iswspace (c) || !(iswalnum (c) || c == '_')) ++#endif /* UTF8 */ + return 0; + + /* search start of word to be completed */ +@@ -2731,11 +3037,19 @@ static int edit_find_word_start (WEdit *edit, long *word_start, int *word_len) + return 0; + + last = c; +- c = (unsigned char) edit_get_byte (edit, edit->curs1 - i); ++ c = edit_get_byte (edit, edit->curs1 - i); + ++#ifndef UTF8 + if (!(isalnum (c) || c == '_')) { ++#else /* UTF8 */ ++ if (!(iswalnum (c) || c == '_')) { ++#endif /* UTF8 */ + /* return if word starts with digit */ ++#ifndef UTF8 + if (isdigit (last)) ++#else /* UTF8 */ ++ if (iswdigit (last)) ++#endif /* UTF8 */ + return 0; + + *word_start = edit->curs1 - (i - 1); /* start found */ +@@ -2768,7 +3082,7 @@ edit_collect_completions (WEdit *edit, long start, int word_len, + int *num) + { + int len, max_len = 0, i, skip; +- unsigned char *bufpos; ++ mc_wchar_t *bufpos; + + /* collect max MAX_WORD_COMPLETIONS completions */ + while (*num < MAX_WORD_COMPLETIONS) { +@@ -2787,11 +3101,16 @@ edit_collect_completions (WEdit *edit, long start, int word_len, + buffers1[start >> S_EDIT_BUF_SIZE][start & M_EDIT_BUF_SIZE]; + skip = 0; + for (i = 0; i < *num; i++) { ++#ifndef UTF8 + if (strncmp + ((char *) &compl[i].text[word_len], +- (char *) &bufpos[word_len], max (len, +- compl[i].len) - +- word_len) == 0) { ++ (char *) &bufpos[word_len], ++#else /* UTF8 */ ++ if (wcsncmp ++ ((wchar_t *) &compl[i].text[word_len], ++ (wchar_t *) &bufpos[word_len], ++#endif /* UTF8 */ ++ max (len, compl[i].len) - word_len) == 0) { + skip = 1; + break; /* skip it, already added */ + } +@@ -2799,7 +3118,7 @@ edit_collect_completions (WEdit *edit, long start, int word_len, + if (skip) + continue; + +- compl[*num].text = g_malloc (len + 1); ++ compl[*num].text = g_malloc ((len + 1) * sizeof(mc_wchar_t)); + compl[*num].len = len; + for (i = 0; i < len; i++) + compl[*num].text[i] = *(bufpos + i); +@@ -2813,6 +3132,18 @@ edit_collect_completions (WEdit *edit, long start, int word_len, + return max_len; + } + ++#ifdef UTF8 ++int edit_print_string (WEdit * e, const char *s) ++{ ++ int i; ++ mc_wchar_t *ws = mbstr_to_wchar(s); ++ i = edit_print_wstring (e, ws); ++ g_free(ws); ++ return i; ++} ++ ++#endif /* UTF8 */ ++ + + /* let the user select its preferred completion */ + static void +@@ -2825,6 +3156,9 @@ edit_completion_dialog (WEdit * edit, int max_len, int word_len, + WListbox *compl_list; + int compl_dlg_h; /* completion dialog height */ + int compl_dlg_w; /* completion dialog width */ ++#ifdef UTF8 ++ char *mbtext; ++#endif /* UTF8 */ + + /* calculate the dialog metrics */ + compl_dlg_h = num_compl + 2; +@@ -2860,9 +3194,18 @@ edit_completion_dialog (WEdit * edit, int max_len, int word_len, + add_widget (compl_dlg, compl_list); + + /* fill the listbox with the completions */ ++#ifndef UTF8 + for (i = 0; i < num_compl; i++) + listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, + (char *) compl[i].text, NULL); ++#else /* UTF8 */ ++ for (i = 0; i < num_compl; i++) { ++ mbtext = wchar_to_mbstr(compl[i].text); ++ listbox_add_item (compl_list, LISTBOX_APPEND_AT_END, 0, ++ mbtext, NULL); ++ g_free(mbtext); ++ } ++#endif /* UTF8 */ + + /* pop up the dialog */ + run_dlg (compl_dlg); +@@ -2870,9 +3213,17 @@ edit_completion_dialog (WEdit * edit, int max_len, int word_len, + /* apply the choosen completion */ + if (compl_dlg->ret_value == B_ENTER) { + listbox_get_current (compl_list, &curr, NULL); +- if (curr) ++ if (curr){ ++#ifndef UTF8 + for (curr += word_len; *curr; curr++) + edit_insert (edit, *curr); ++#else /* UTF8 */ ++ mc_wchar_t *wc, *wccurr = mbstr_to_wchar(curr); ++ for (wc = wccurr + word_len; *wc; wc++) ++ edit_insert (edit, *wc); ++ g_free(wccurr); ++#endif /* UTF8 */ ++ } + } + + /* destroy dialog before return */ +@@ -2889,8 +3240,9 @@ edit_complete_word_cmd (WEdit *edit) + { + int word_len = 0, i, num_compl = 0, max_len; + long word_start = 0; +- unsigned char *bufpos; +- char *match_expr; ++ mc_wchar_t *bufpos; ++ mc_wchar_t *match_expr; ++ char *mbmatch_expr; + struct selection compl[MAX_WORD_COMPLETIONS]; /* completions */ + + /* don't want to disturb another search */ +@@ -2907,16 +3259,32 @@ edit_complete_word_cmd (WEdit *edit) + /* prepare match expression */ + bufpos = &edit->buffers1[word_start >> S_EDIT_BUF_SIZE] + [word_start & M_EDIT_BUF_SIZE]; ++ ++ match_expr = g_malloc((word_len + 14) * sizeof(mc_wchar_t)); ++#ifndef UTF8 + match_expr = g_strdup_printf ("%.*s[a-zA-Z_0-9]+", word_len, bufpos); ++#else /* UTF8 */ ++ wcsncpy (match_expr, bufpos, word_len); ++ match_expr[word_len] = '\0'; ++ wcscat (match_expr, L"[a-zA-Z_0-9]+"); ++#endif /* UTF8 */ + + /* init search: backward, regexp, whole word, case sensitive */ + edit_set_search_parameters (0, 1, 1, 1, 1); + + /* collect the possible completions */ + /* start search from curs1 down to begin of file */ ++#ifndef UTF8 + max_len = + edit_collect_completions (edit, word_start, word_len, match_expr, + (struct selection *) &compl, &num_compl); ++#else /* UTF8 */ ++ mbmatch_expr = wchar_to_mbstr(match_expr); ++ max_len = ++ edit_collect_completions (edit, word_start, word_len, mbmatch_expr, ++ (struct selection *) &compl, &num_compl); ++ g_free(mbmatch_expr); ++#endif /* UTF8 */ + + if (num_compl > 0) { + /* insert completed word if there is only one match */ +@@ -2951,7 +3319,7 @@ void + edit_select_codepage_cmd (WEdit *edit) + { + #ifdef HAVE_CHARSET +- do_select_codepage (); ++ do_select_codepage (_(" Choose codepage ")); + edit->force = REDRAW_COMPLETELY; + edit_refresh_cmd (edit); + #endif +diff --git a/edit/editdraw.c b/edit/editdraw.c +index 86ea3f9..654f0b3 100644 +--- a/edit/editdraw.c ++++ b/edit/editdraw.c +@@ -71,11 +71,26 @@ static void status_string (WEdit * edit, char *s, int w) + * as decimal and as hex. + */ + if (edit->curs1 < edit->last_byte) { +- unsigned char cur_byte = edit_get_byte (edit, edit->curs1); ++ mc_wchar_t cur_byte = edit_get_byte (edit, edit->curs1); ++ mc_wchar_t cur_byte2 = cur_byte; ++#ifndef UTF8 + g_snprintf (byte_str, sizeof (byte_str), "%c %3d 0x%02X", + is_printable (cur_byte) ? cur_byte : '.', +- (int) cur_byte, +- (unsigned) cur_byte); ++#else /* UTF8 */ ++ /* In 8-bit locales show the byte itself instead of its Unicode value */ ++ if (MB_CUR_MAX == 1) { ++ unsigned char cur_8bit_byte; ++ mbstate_t mbs; ++ memset (&mbs, 0, sizeof (mbs)); ++ if (wcrtomb(&cur_8bit_byte, cur_byte, &mbs) == 1) { ++ cur_byte = cur_8bit_byte; ++ } ++ } ++ g_snprintf (byte_str, sizeof(byte_str), "%lc %3d 0x%02X", ++ iswprint(cur_byte2) ? cur_byte2 : '.', ++#endif /* UTF8 */ ++ (int) cur_byte, ++ (unsigned) cur_byte); + } else { + strcpy (byte_str, ""); + } +@@ -207,11 +222,16 @@ void edit_scroll_screen_over_cursor (WEdit * edit) + #define lowlevel_set_color(x) attrset(MY_COLOR_PAIR(color)) + #endif + ++struct line_s { ++ mc_wchar_t ch; ++ unsigned int style; ++}; ++ + static void + print_to_widget (WEdit *edit, long row, int start_col, int start_col_real, +- long end_col, unsigned int line[]) ++ long end_col, struct line_s line[]) + { +- unsigned int *p; ++ struct line_s *p; + + int x = start_col_real + EDIT_TEXT_HORIZONTAL_OFFSET; + int x1 = start_col + EDIT_TEXT_HORIZONTAL_OFFSET; +@@ -225,9 +245,9 @@ print_to_widget (WEdit *edit, long row, int start_col, int start_col_real, + edit_move (x1 + FONT_OFFSET_X, y + FONT_OFFSET_Y); + p = line; + +- while (*p) { ++ while (p->ch) { + int style; +- int textchar; ++ mc_wchar_t textchar; + int color; + + if (cols_to_skip) { +@@ -236,9 +256,9 @@ print_to_widget (WEdit *edit, long row, int start_col, int start_col_real, + continue; + } + +- style = *p & 0xFF00; +- textchar = *p & 0xFF; +- color = *p >> 16; ++ style = p->style & 0xFF00; ++ textchar = p->ch; ++ color = p->style >> 16; + + if (style & MOD_ABNORMAL) { + /* Non-printable - use black background */ +@@ -267,8 +287,11 @@ print_to_widget (WEdit *edit, long row, int start_col, int start_col_real, + lowlevel_set_color (color); + } + } +- ++#ifdef UTF8 ++ SLsmg_write_nwchars(&textchar, 1); ++#else + addch (textchar); ++#endif + p++; + } + } +@@ -280,11 +303,11 @@ static void + edit_draw_this_line (WEdit *edit, long b, long row, long start_col, + long end_col) + { +- static unsigned int line[MAX_LINE_LEN]; +- unsigned int *p = line; ++ struct line_s line[MAX_LINE_LEN]; ++ struct line_s *p = line; + long m1 = 0, m2 = 0, q, c1, c2; + int col, start_col_real; +- unsigned int c; ++ mc_wint_t c; + int color; + int i; + +@@ -309,62 +332,88 @@ edit_draw_this_line (WEdit *edit, long b, long row, long start_col, + } + + while (col <= end_col - edit->start_col) { +- *p = 0; ++ p->ch = 0; ++ p->style = 0; + if (q == edit->curs1) +- *p |= MOD_CURSOR; ++ p->style |= MOD_CURSOR; + if (q >= m1 && q < m2) { + if (column_highlighting) { + int x; + x = edit_move_forward3 (edit, b, 0, q); + if (x >= c1 && x < c2) +- *p |= MOD_MARKED; ++ p->style |= MOD_MARKED; + } else +- *p |= MOD_MARKED; ++ p->style |= MOD_MARKED; + } + if (q == edit->bracket) +- *p |= MOD_BOLD; ++ p->style |= MOD_BOLD; + if (q >= edit->found_start + && q < edit->found_start + edit->found_len) +- *p |= MOD_BOLD; ++ p->style |= MOD_BOLD; + c = edit_get_byte (edit, q); + /* we don't use bg for mc - fg contains both */ + edit_get_syntax_color (edit, q, &color); +- *p |= color << 16; ++ p->style |= color << 16; + switch (c) { + case '\n': + col = end_col - edit->start_col + 1; /* quit */ +- *(p++) |= ' '; ++ p->ch = ' '; ++ p++; + break; + case '\t': + i = TAB_SIZE - ((int) col % TAB_SIZE); + col += i; + if (use_colors && visible_tabs) { +- c = (*p & ~MOD_CURSOR) | MOD_WHITESPACE; ++ c = (p->style & ~MOD_CURSOR) | MOD_WHITESPACE; + if (i > 2) { +- *(p++) |= '<' | MOD_WHITESPACE; +- while (--i > 1) +- *(p++) = c | '-'; +- *(p++) = c | '>'; ++ p->ch = '<'; ++ p->style |= MOD_WHITESPACE; ++ p++; ++ while (--i > 1) { ++ p->ch = '-'; ++ p->style = c; ++ p++; ++ } ++ p->ch = '>'; ++ p->style = c; ++ p++; + } else if (i > 1) { +- *(p++) |= '<' | MOD_WHITESPACE; +- *(p++) = c | '>'; +- } else +- *(p++) |= '>' | MOD_WHITESPACE; ++ p->ch = '<'; ++ p->style |= MOD_WHITESPACE; ++ p++; ++ p->ch = '>'; ++ p->style = c; ++ p++; ++ } else { ++ p->ch = '>'; ++ p->style |= MOD_WHITESPACE; ++ p++; ++ } + } else if (use_colors && visible_tws && q >= tws) { +- *p |= '.' | MOD_WHITESPACE; +- c = *(p++) & ~MOD_CURSOR; +- while (--i) +- *(p++) = c; ++ p->ch = '.'; ++ p->style |= MOD_WHITESPACE; ++ c = p->style & ~MOD_CURSOR; ++ p++; ++ while (--i) { ++ p->ch = '.'; ++ p->style = c; ++ p++; ++ } + } else { +- *p |= ' '; +- c = *(p++) & ~MOD_CURSOR; +- while (--i) +- *(p++) = c; ++ p->ch = ' '; ++ c = p->style & ~MOD_CURSOR; ++ p++; ++ while (--i) { ++ p->ch = ' '; p->style = c; ++ p++; ++ } + } + break; + case ' ': + if (use_colors && visible_tws && q >= tws) { +- *(p++) |= '.' | MOD_WHITESPACE; ++ p->ch = '.'; ++ p->style |= MOD_WHITESPACE; ++ p++; + col++; + break; + } +@@ -374,22 +423,47 @@ edit_draw_this_line (WEdit *edit, long b, long row, long start_col, + + /* Caret notation for control characters */ + if (c < 32) { +- *(p++) = '^' | MOD_ABNORMAL; +- *(p++) = (c + 0x40) | MOD_ABNORMAL; ++ p->ch = '^'; ++ p->style = MOD_ABNORMAL; ++ p++; ++ p->ch = c + 0x40; ++ p->style = MOD_ABNORMAL; + col += 2; + break; + } + if (c == 127) { +- *(p++) = '^' | MOD_ABNORMAL; +- *(p++) = '?' | MOD_ABNORMAL; ++ p->ch = '^'; ++ p->style = MOD_ABNORMAL; ++ p++; ++ p->ch = '?'; ++ p->style = MOD_ABNORMAL; ++ p++; + col += 2; + break; + } + +- if (is_printable (c)) { +- *(p++) |= c; ++#ifndef UTF8 ++ if (is_printable (c) ++#else /* UTF8 */ ++ if (iswprint (c) ++#ifdef __STDC_ISO_10646__ ++ && (c < BINARY_CHAR_OFFSET || c >= (BINARY_CHAR_OFFSET + 256)) ++#endif ++#endif /* UTF8 */ ++ ) { ++ p->ch = c; ++ p++; ++ ++#ifdef UTF8 ++ i = wcwidth(c); ++ if (i > 1) { ++ col += i - 1; ++ } ++#endif /* UTF8 */ + } else { +- *(p++) = '.' | MOD_ABNORMAL; ++ p->ch = '.'; ++ p->style = MOD_ABNORMAL; ++ p++; + } + col++; + break; +@@ -400,7 +474,7 @@ edit_draw_this_line (WEdit *edit, long b, long row, long start_col, + } else { + start_col_real = start_col = 0; + } +- *p = 0; ++ p->ch = 0; + + print_to_widget (edit, row, start_col, start_col_real, end_col, line); + } +diff --git a/edit/editkeys.c b/edit/editkeys.c +index 2cc6add..111d377 100644 +--- a/edit/editkeys.c ++++ b/edit/editkeys.c +@@ -183,10 +183,10 @@ static const edit_key_map_type common_key_map[] = { + * 'command' is one of the editor commands from editcmddef.h. + */ + int +-edit_translate_key (WEdit *edit, long x_key, int *cmd, int *ch) ++edit_translate_key (WEdit *edit, long x_key, int *cmd, mc_wint_t *ch) + { + int command = CK_Insert_Char; +- int char_for_insertion = -1; ++ mc_wint_t char_for_insertion = -1; + int i = 0; + int extmod = 0; + const edit_key_map_type *key_map = NULL; +@@ -243,9 +243,30 @@ edit_translate_key (WEdit *edit, long x_key, int *cmd, int *ch) + /* an ordinary insertable character */ + if (x_key < 256 && !extmod) { + int c = convert_from_input_c (x_key); ++#ifdef UTF8 ++ mbstate_t mbs; ++ int res; ++ mc_wchar_t wc; + ++ memset (&mbs, 0, sizeof (mbs)); ++ ++ if (edit->charpoint >= MB_CUR_MAX) edit->charpoint = 0; ++ ++ edit->charbuf[edit->charpoint++] = c; ++ ++ res = mbrtowc(&wc, (char *)edit->charbuf, edit->charpoint, &mbs); ++ if (res < 0) { ++ if (res != -2) edit->charpoint = 0; /* broken multibyte char, skip */ ++ return 0; ++ } ++ edit->charpoint = 0; ++ ++ if (iswprint (wc)) { ++ char_for_insertion = wc; ++#else + if (is_printable (c)) { + char_for_insertion = c; ++#endif /* UTF8 */ + goto fin; + } + } +@@ -284,7 +305,7 @@ edit_translate_key (WEdit *edit, long x_key, int *cmd, int *ch) + *cmd = command; + *ch = char_for_insertion; + +- if (command == CK_Insert_Char && char_for_insertion == -1) { ++ if (command == CK_Insert_Char && char_for_insertion == (mc_wint_t)-1) { + /* unchanged, key has no function here */ + return 0; + } +diff --git a/edit/editwidget.c b/edit/editwidget.c +index 8ae8cf0..286a844 100644 +--- a/edit/editwidget.c ++++ b/edit/editwidget.c +@@ -333,7 +333,8 @@ edit_callback (Widget *w, widget_msg_t msg, int parm) + + case WIDGET_KEY: + { +- int cmd, ch; ++ int cmd; ++ mc_wint_t ch; + + /* The user may override the access-keys for the menu bar. */ + if (edit_translate_key (e, parm, &cmd, &ch)) { +diff --git a/edit/wordproc.c b/edit/wordproc.c +index fc16136..25a534e 100644 +--- a/edit/wordproc.c ++++ b/edit/wordproc.c +@@ -40,7 +40,12 @@ + + #define tab_width option_tab_spacing + ++#ifndef UTF8 + #define NO_FORMAT_CHARS_START "-+*\\,.;:&>" ++#else /* UTF8 */ ++#define NO_FORMAT_CHARS_START L"-+*\\,.;:&>" ++#endif /* UTF8 */ ++ + #define FONT_MEAN_WIDTH 1 + + static long +@@ -57,14 +62,21 @@ line_start (WEdit *edit, long line) + p = edit_move_forward (edit, p, line - l, 0); + + p = edit_bol (edit, p); ++ ++#ifndef UTF8 + while (strchr ("\t ", edit_get_byte (edit, p))) ++#else /* UTF8 */ ++ while (wcschr (L"\t ", edit_get_byte (edit, p))) ++#endif /* UTF8 */ ++ + p++; + return p; + } + + static int bad_line_start (WEdit * edit, long p) + { +- int c; ++ mc_wint_t c; ++ + c = edit_get_byte (edit, p); + if (c == '.') { /* `...' is acceptable */ + if (edit_get_byte (edit, p + 1) == '.') +@@ -78,7 +90,13 @@ static int bad_line_start (WEdit * edit, long p) + return 0; /* `---' is acceptable */ + return 1; + } ++ ++#ifndef UTF8 + if (strchr (NO_FORMAT_CHARS_START, c)) ++#else /* UTF8 */ ++ if (wcschr (NO_FORMAT_CHARS_START, c)) ++#endif /* UTF8 */ ++ + return 1; + return 0; + } +@@ -131,33 +149,37 @@ end_paragraph (WEdit *edit, int force) + i - edit->curs_line, 0)); + } + +-static unsigned char * ++static mc_wchar_t * + get_paragraph (WEdit *edit, long p, long q, int indent, int *size) + { +- unsigned char *s, *t; ++ mc_wchar_t *s, *t; + #if 0 +- t = g_malloc ((q - p) + 2 * (q - p) / option_word_wrap_line_length + +- 10); ++ t = g_malloc (((q - p) + 2 * (q - p) / option_word_wrap_line_length + ++ 10) * sizeof(mc_wchar_t)); + #else +- t = g_malloc (2 * (q - p) + 100); ++ t = g_malloc ((2 * (q - p) + 100) * sizeof(mc_wchar_t)); + #endif + if (!t) + return 0; + for (s = t; p < q; p++, s++) { + if (indent) + if (edit_get_byte (edit, p - 1) == '\n') ++#ifndef UTF8 + while (strchr ("\t ", edit_get_byte (edit, p))) ++#else /* UTF8 */ ++ while (wcschr (L"\t ", edit_get_byte (edit, p))) ++#endif /* UTF8 */ + p++; + *s = edit_get_byte (edit, p); + } +- *size = (unsigned long) s - (unsigned long) t; ++ *size = s - t; + t[*size] = '\n'; + return t; + } + +-static void strip_newlines (unsigned char *t, int size) ++static void strip_newlines (mc_wchar_t *t, int size) + { +- unsigned char *p = t; ++ mc_wchar_t *p = t; + while (size--) { + *p = *p == '\n' ? ' ' : *p; + p++; +@@ -174,7 +196,7 @@ static inline int next_tab_pos (int x) + { + return x += tab_width - x % tab_width; + } +-static int line_pixel_length (unsigned char *t, long b, int l) ++static int line_pixel_length (mc_wchar_t *t, long b, int l) + { + int x = 0, c, xn = 0; + for (;;) { +@@ -198,7 +220,7 @@ static int line_pixel_length (unsigned char *t, long b, int l) + } + + static int +-next_word_start (unsigned char *t, int q, int size) ++next_word_start (mc_wchar_t *t, int q, int size) + { + int i; + int saw_ws = 0; +@@ -222,7 +244,7 @@ next_word_start (unsigned char *t, int q, int size) + + /* find the start of a word */ + static int +-word_start (unsigned char *t, int q, int size) ++word_start (mc_wchar_t *t, int q, int size) + { + int i = q; + if (t[q] == ' ' || t[q] == '\t') +@@ -241,7 +263,7 @@ word_start (unsigned char *t, int q, int size) + } + + /* replaces ' ' with '\n' to properly format a paragraph */ +-static void format_this (unsigned char *t, int size, int indent) ++static void format_this (mc_wchar_t *t, int size, int indent) + { + int q = 0, ww; + strip_newlines (t, size); +@@ -269,7 +291,7 @@ static void format_this (unsigned char *t, int size, int indent) + } + } + +-static void replace_at (WEdit * edit, long q, int c) ++static void replace_at (WEdit * edit, long q, mc_wint_t c) + { + edit_cursor_move (edit, q - edit->curs1); + edit_delete (edit); +@@ -278,18 +300,27 @@ static void replace_at (WEdit * edit, long q, int c) + + /* replaces a block of text */ + static void +-put_paragraph (WEdit * edit, unsigned char *t, long p, int indent, int size) ++put_paragraph (WEdit * edit, mc_wchar_t *t, long p, int indent, int size) + { + long cursor; +- int i, c = 0; ++ int i; ++ mc_wchar_t c = 0; + cursor = edit->curs1; + if (indent) ++#ifndef UTF8 + while (strchr ("\t ", edit_get_byte (edit, p))) ++#else /* UTF8 */ ++ while (wcschr (L"\t ", edit_get_byte (edit, p))) ++#endif /* UTF8 */ + p++; + for (i = 0; i < size; i++, p++) { + if (i && indent) { + if (t[i - 1] == '\n' && c == '\n') { ++#ifndef UTF8 + while (strchr ("\t ", edit_get_byte (edit, p))) ++#else /* UTF8 */ ++ while (wcschr (L"\t ", edit_get_byte (edit, p))) ++#endif /* UTF8 */ + p++; + } else if (t[i - 1] == '\n') { + long curs; +@@ -301,7 +332,11 @@ put_paragraph (WEdit * edit, unsigned char *t, long p, int indent, int size) + p = edit->curs1; + } else if (c == '\n') { + edit_cursor_move (edit, p - edit->curs1); ++#ifndef UTF8 + while (strchr ("\t ", edit_get_byte (edit, p))) { ++#else /* UTF8 */ ++ while (wcschr (L"\t ", edit_get_byte (edit, p))) { ++#endif /* UTF8 */ + edit_delete (edit); + if (cursor > edit->curs1) + cursor--; +@@ -334,7 +369,7 @@ format_paragraph (WEdit *edit, int force) + { + long p, q; + int size; +- unsigned char *t; ++ mc_wchar_t *t; + int indent = 0; + if (option_word_wrap_line_length < 2) + return; +@@ -348,13 +383,21 @@ format_paragraph (WEdit *edit, int force) + return; + if (!force) { + int i; ++#ifndef UTF8 + if (strchr (NO_FORMAT_CHARS_START, *t)) { ++#else /* UTF8 */ ++ if (wcschr (NO_FORMAT_CHARS_START, *t)) { ++#endif /* UTF8 */ + g_free (t); + return; + } + for (i = 0; i < size - 1; i++) { + if (t[i] == '\n') { ++#ifndef UTF8 + if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) { ++#else /* UTF8 */ ++ if (wcschr (NO_FORMAT_CHARS_START "\t", t[i + 1])) { ++#endif /* UTF8 */ + g_free (t); + return; + } +diff --git a/po/ru.po b/po/ru.po +index 5ee11d0..76c3a6b 100644 +--- a/po/ru.po ++++ b/po/ru.po +@@ -3650,5 +3650,30 @@ msgstr " + #~ " ÔÅÐÅÒØ ÈÒÁÎÑÔÓÑ × ËÁÔÁÌÏÇÅ ~/.mc, ÓÔÁÒÙÅ \n" + #~ " ÆÁÊÌÙ ÓÅÊÞÁÓ ÔÕÄÁ ÐÅÒÅÍÅÝÅÎÙ\n" + +-#~ msgid "%s bytes in %d files" +-#~ msgstr "%s ÂÁÊÔ × %d ÆÁÊÌÁÈ" ++#: messages for recode patch ++msgid "Panel &codepage" ++msgstr "ëÏÄÉÒÏ×ËÁ ÐÁÎÅÌÉ" ++ ++msgid " Choose codepage " ++msgstr " ÷ÙÂÅÒÉÔÅ ËÏÄÉÒÏ×ËÕ" ++ ++msgid " Choose panel codepage " ++msgstr " ÷ÙÂÅÒÉÔÅ ËÏÄÉÒÏ×ËÕ ÐÁÎÅÌÉ " ++ ++msgid " Choose default FTP codepage " ++msgstr " ÷ÙÂÅÒÉÔÅ ËÏÄÉÒÏ×ËÕ FTP ÐÏ ÕÍÏÌÞÁÎÉÀ " ++ ++msgid "FTP default codepage:" ++msgstr "ëÏÄÉÒÏ×ËÁ FTP ÐÏ ÕÍÏÌÞÁÎÉÀ:" ++ ++msgid "Recode file names:" ++msgstr "ðÅÒÅËÏÄÉÒÏ×ÁÔØ ÉÍÅÎÁ:" ++ ++msgid "Recoding works only with COPY/MOVE operation" ++msgstr "ðÅÒÅËÏÄÉÒÏ×ËÁ ÒÁÂÏÔÁÅÔ ÔÏÌØËÏ ÄÌÑ ÏÐÅÒÁÃÉÊ ËÏÐÉÒÏ×ÁÎÉÑ/ÐÅÒÅÍÅÝÅÎÉÑ" ++ ++msgid " Choose \"FROM\" codepage for COPY/MOVE operaion " ++msgstr" ÷ÙÂÅÒÉÔÅ ÎÁÞÁÌØÎÕÀ ËÏÄÉÒÏ×ËÕ ÄÌÑ ÏÐÅÒÁÃÉÉ ËÏÐÉÒÏ×ÁÎÉÑ/ÐÅÒÅÍÅÝÅÎÉÑ " ++ ++msgid " Choose \"TO\" codepage for COPY/MOVE operaion " ++msgstr" ÷ÙÂÅÒÉÔÅ ËÏÎÅÞÎÕÀ ËÏÄÉÒÏ×ËÕ ÄÌÑ ÏÐÅÒÁÃÉÉ ËÏÐÉÒÏ×ÁÎÉÑ/ÐÅÒÅÍÅÝÅÎÉÑ " +diff --git a/src/Makefile.am b/src/Makefile.am +index d43b198..90bd1b1 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -41,7 +41,8 @@ endif + mc_LDADD = $(EDITLIB) $(SLANGLIB) $(VFSLIB) \ + $(INTLLIBS) $(GLIB_LIBS) $(MCLIBS) $(LIBICONV) + +-CHARSET_SRC = charsets.c charsets.h selcodepage.c selcodepage.h ++CHARSET_SRC = charsets.c charsets.h selcodepage.c selcodepage.h \ ++ recode.c recode.h + + SRCS = achown.c achown.h background.c background.h boxes.c boxes.h \ + chmod.c chmod.h chown.c chown.h cmd.c cmd.h color.c color.h \ +@@ -58,7 +59,7 @@ SRCS = achown.c achown.h background.c background.h boxes.c boxes.h \ + menu.c menu.h mountlist.c mountlist.h mouse.c mouse.h myslang.h \ + option.c option.h panel.h panelize.c panelize.h poptalloca.h \ + popt.c poptconfig.c popt.h popthelp.c poptint.h poptparse.c \ +- profile.c profile.h regex.c rxvt.c screen.c setup.c setup.h \ ++ profile.c profile.h regex.c rxvt.c screen.c screen.h setup.c setup.h \ + slint.c subshell.c subshell.h textconf.c textconf.h \ + tree.c tree.h treestore.c treestore.h timefmt.h tty.c tty.h user.c \ + user.h util.c util.h utilunix.c view.c view.h vfsdummy.h widget.c \ +diff --git a/src/achown.c b/src/achown.c +index 72ddcad..f1f3024 100644 +--- a/src/achown.c ++++ b/src/achown.c +@@ -585,6 +585,12 @@ init_chown_advanced (void) + b_att[2] = button_new (XTRACT (6)); + b_user = button_new (XTRACT (5)); + b_group = button_new (XTRACT (4)); ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) { ++ b_user->text = g_realloc (b_user->text, MB_CUR_MAX * 15 + 1); ++ b_group->text = g_realloc (b_group->text, MB_CUR_MAX * 15 + 1); ++ } ++#endif + + add_widget (ch_dlg, b_group); + add_widget (ch_dlg, b_user); +diff --git a/src/boxes.c b/src/boxes.c +index 0ff72d4..82a0e1b 100644 +--- a/src/boxes.c ++++ b/src/boxes.c +@@ -53,6 +53,7 @@ + #ifdef HAVE_CHARSET + #include "charsets.h" + #include "selcodepage.h" ++#include "recode.h" + #endif + + #ifdef USE_NETCODE +@@ -154,23 +155,23 @@ display_init (int radio_sel, char *init_text, int _check_status, + display_title = _(display_title); + for (i = 0; i < LIST_TYPES; i++) { + displays[i] = _(displays[i]); +- if ((l = strlen (displays[i])) > maxlen) ++ if ((l = mbstrlen (displays[i])) > maxlen) + maxlen = l; + } + +- i = strlen (ok_button) + 5; +- l = strlen (cancel_button) + 3; ++ i = mbstrlen (ok_button) + 5; ++ l = mbstrlen (cancel_button) + 3; + l = max (i, l); + + i = maxlen + l + 16; + if (i > DISPLAY_X) + DISPLAY_X = i; + +- i = strlen (user_mini_status) + 13; ++ i = mbstrlen (user_mini_status) + 13; + if (i > DISPLAY_X) + DISPLAY_X = i; + +- i = strlen (display_title) + 10; ++ i = mbstrlen (display_title) + 10; + if (i > DISPLAY_X) + DISPLAY_X = i; + +@@ -290,20 +291,20 @@ sort_box (sortfn *sort_fn, int *reverse, int *case_sensitive, int *exec_first) + int maxlen = 0; + for (i = SORT_TYPES - 1; i >= 0; i--) { + sort_orders_names[i] = _(sort_orders[i].sort_name); +- r = strlen (sort_orders_names[i]); ++ r = mbstrlen (sort_orders_names[i]); + if (r > maxlen) + maxlen = r; + } + + check_pos = maxlen + 9; + +- r = strlen (reverse_label) + 4; +- i = strlen (case_label) + 4; ++ r = mbstrlen (reverse_label) + 4; ++ i = mbstrlen (case_label) + 4; + if (i > r) + r = i; + +- l = strlen (ok_button) + 6; +- i = strlen (cancel_button) + 4; ++ l = mbstrlen (ok_button) + 6; ++ i = mbstrlen (cancel_button) + 4; + if (i > l) + l = i; + +@@ -312,7 +313,7 @@ sort_box (sortfn *sort_fn, int *reverse, int *case_sensitive, int *exec_first) + if (i > SORT_X) + SORT_X = i; + +- i = strlen (sort_title) + 6; ++ i = mbstrlen (sort_title) + 6; + if (i > SORT_X) + SORT_X = i; + +@@ -413,7 +414,7 @@ confirm_box (void) + while (i--) + { + conf_widgets [i].text = _(conf_widgets [i].text); +- l1 = strlen (conf_widgets [i].text) + 3; ++ l1 = mbstrlen (conf_widgets [i].text) + 3; + if (l1 > maxlen) + maxlen = l1; + } +@@ -428,8 +429,8 @@ confirm_box (void) + * And this for the case when buttons with some space to the right + * do not fit within 2/6 + */ +- l1 = strlen (conf_widgets [0].text) + 3; +- i = strlen (conf_widgets [1].text) + 5; ++ l1 = mbstrlen (conf_widgets [0].text) + 3; ++ i = mbstrlen (conf_widgets [1].text) + 5; + if (i > l1) + l1 = i; + +@@ -459,8 +460,8 @@ confirm_box (void) + } + } + +-#define DISPY 11 +-#define DISPX 46 ++#define DISPY 13 ++#define DISPX 35 + + + #ifndef HAVE_CHARSET +@@ -502,11 +503,11 @@ display_bits_box (void) + { + display_widgets [i].text = _(display_widgets[i].text); + display_bits_str [i] = _(display_bits_str [i]); +- l1 = strlen (display_bits_str [i]); ++ l1 = mbstrlen (display_bits_str [i]); + if (l1 > maxlen) + maxlen = l1; + } +- l1 = strlen (display_widgets [2].text); ++ l1 = mbstrlen (display_widgets [2].text); + if (l1 > maxlen) + maxlen = l1; + +@@ -514,8 +515,8 @@ display_bits_box (void) + display_bits.xlen = (maxlen + 5) * 6 / 4; + + /* See above confirm_box */ +- l1 = strlen (display_widgets [0].text) + 3; +- i = strlen (display_widgets [1].text) + 5; ++ l1 = mbstrlen (display_widgets [0].text) + 3; ++ i = mbstrlen (display_widgets [1].text) + 5; + if (i > l1) + l1 = i; + +@@ -556,23 +557,58 @@ display_bits_box (void) + + + static int new_display_codepage; ++static int new_ftp_codepage; + +-static WLabel *cplabel; + static WCheck *inpcheck; + ++static WButton *cpbutton; ++static WButton *cpbutton_ftp; ++ + static int + sel_charset_button (int action) + { + const char *cpname; + char buf[64]; +- new_display_codepage = select_charset (new_display_codepage, 1); ++ new_display_codepage = select_charset (new_display_codepage, 1, _(" Choose input codepage ")); + cpname = (new_display_codepage < 0) + ? _("Other 8 bit") + : codepages[new_display_codepage].name; + + /* avoid strange bug with label repainting */ +- g_snprintf (buf, sizeof (buf), "%-27s", cpname); +- label_set_text (cplabel, buf); ++ sprintf( buf, "%s", cpname ); ++ button_set_text (cpbutton, buf); ++ ++ if(new_display_codepage<0) new_ftp_codepage=-1; ++ cpname = (new_ftp_codepage < 0) ++ ? _("Other 8 bit") ++ : codepages[ new_ftp_codepage ].name; ++ sprintf( buf, "%s", cpname ); ++ button_set_text (cpbutton_ftp, buf); ++ ++ return 0; ++} ++ ++static int sel_charset_button_ftp(int action) { ++ char *cpname, buf[64]; ++ if(new_display_codepage>0) { ++ new_ftp_codepage = select_charset(new_ftp_codepage, 0, _(" Choose default FTP codepage ")); ++ cpname = (new_display_codepage < 0) ++ ? _("Other 8 bit") ++ : codepages[ new_display_codepage ].name; ++ sprintf( buf, "%s", cpname ); ++ button_set_text( cpbutton, buf ); ++ cpname = (new_ftp_codepage < 0) ++ ? _("Other 8 bit") ++ : codepages[ new_ftp_codepage ].name; ++ sprintf( buf, "%s", cpname ); ++ button_set_text( cpbutton_ftp, buf ); ++ } ++ else { ++ message( 1, _(" Warning "), ++ _("To use this feature select your codepage in\n" ++ "Setup / Display Bits dialog!\n" ++ "Do not forget to save options." )); ++ } + return 0; + } + +@@ -594,9 +630,6 @@ init_disp_bits_box (void) + cpname = (new_display_codepage < 0) + ? _("Other 8 bit") + : codepages[new_display_codepage].name; +- cplabel = label_new (4, 4, cpname); +- add_widget (dbits_dlg, cplabel); +- + add_widget (dbits_dlg, + button_new (DISPY - 3, DISPX / 2 + 3, B_CANCEL, + NORMAL_BUTTON, _("&Cancel"), 0)); +@@ -605,13 +638,30 @@ init_disp_bits_box (void) + 0)); + + inpcheck = +- check_new (6, 4, !use_8th_bit_as_meta, _("F&ull 8 bits input")); ++ check_new (8, 4, !use_8th_bit_as_meta, _("F&ull 8 bits input")); + add_widget (dbits_dlg, inpcheck); + +- cpname = _("&Select"); +- add_widget (dbits_dlg, +- button_new (4, DISPX - 8 - strlen (cpname), B_USER, +- NORMAL_BUTTON, cpname, sel_charset_button)); ++ ++ add_widget( dbits_dlg, label_new( 5, 4, _("FTP default codepage:"))); ++ if(n_codepages>0) { ++ cpname = (new_display_codepage < 0) ++ ? _("Other 8 bit") ++ : codepages[ new_display_codepage ].name; ++ } ++ else cpname= _("Other 8 bit"); ++ cpbutton=button_new(4, 5, B_USER, ++ NORMAL_BUTTON, cpname, sel_charset_button); ++ ++ if(n_codepages>0) { ++ cpname = (new_ftp_codepage < 0) ++ ? _("Other 8 bit") ++ : codepages[ new_ftp_codepage ].name; ++ } ++ else cpname= _("Other 8 bit"); ++ cpbutton_ftp=button_new(6, 5, B_USER, ++ NORMAL_BUTTON, cpname, sel_charset_button_ftp); ++ add_widget( dbits_dlg, cpbutton_ftp); ++ add_widget (dbits_dlg, cpbutton); + + return dbits_dlg; + } +@@ -621,6 +671,7 @@ display_bits_box (void) + { + Dlg_head *dbits_dlg; + new_display_codepage = display_codepage; ++ new_ftp_codepage = ftp_codepage; + + application_keypad_mode (); + dbits_dlg = init_disp_bits_box (); +@@ -641,6 +692,17 @@ display_bits_box (void) + && display_codepage != 1) ? 128 : 160; + #endif + use_8th_bit_as_meta = !(inpcheck->state & C_BOOL); ++ ++ ftp_codepage=new_ftp_codepage; ++ if(display_codepage<=0) { ++ panel_reset_codepage(left_panel); ++ paint_dir(left_panel); ++ display_mini_info(left_panel); ++ panel_reset_codepage(right_panel); ++ paint_dir(right_panel); ++ display_mini_info(right_panel); ++ } ++ + } + destroy_dlg (dbits_dlg); + repaint_screen (); +@@ -821,7 +883,7 @@ cd_dialog (void) + quick_widgets [1].y_divisions = + quick_widgets [0].y_divisions = Quick_input.ylen = 5; + +- len = strlen (quick_widgets [1].text); ++ len = mbstrlen (quick_widgets [1].text); + + quick_widgets [0].relative_x = + quick_widgets [1].relative_x + len + 1; +@@ -980,7 +1042,7 @@ jobs_cmd (void) + { + job_buttons [i].name = _(job_buttons [i].name); + +- len = strlen (job_buttons [i].name) + 4; ++ len = mbstrlen (job_buttons [i].name) + 4; + JOBS_X = max (JOBS_X, startx + len + 3); + + job_buttons [i].xpos = startx; +@@ -989,7 +1051,7 @@ jobs_cmd (void) + + /* Last button - Ok a.k.a. Cancel :) */ + job_buttons [n_buttons - 1].xpos = +- JOBS_X - strlen (job_buttons [n_buttons - 1].name) - 7; ++ JOBS_X - mbstrlen (job_buttons [n_buttons - 1].name) - 7; + + i18n_flag = 1; + } +@@ -1047,7 +1109,7 @@ vfs_smb_get_authinfo (const char *host, const char *share, const char *domain, + + while (i--) + { +- l1 = strlen (labs [i] = _(labs [i])); ++ l1 = mbstrlen (labs [i] = _(labs [i])); + if (l1 > maxlen) + maxlen = l1; + } +@@ -1057,7 +1119,7 @@ vfs_smb_get_authinfo (const char *host, const char *share, const char *domain, + + for (i = sizeof(buts)/sizeof(buts[0]), l1 = 0; i--; ) + { +- l1 += strlen (buts [i] = _(buts [i])); ++ l1 += mbstrlen (buts [i] = _(buts [i])); + } + l1 += 15; + if (l1 > dialog_x) +@@ -1066,7 +1128,7 @@ vfs_smb_get_authinfo (const char *host, const char *share, const char *domain, + ilen = dialog_x - 7 - maxlen; /* for the case of very long buttons :) */ + istart = dialog_x - 3 - ilen; + +- b2 = dialog_x - (strlen(buts[1]) + 6); ++ b2 = dialog_x - (mbstrlen(buts[1]) + 6); + + i18n_flag = 1; + } +diff --git a/src/charsets.c b/src/charsets.c +index f2e69e0..bac7b3b 100644 +--- a/src/charsets.c ++++ b/src/charsets.c +@@ -123,8 +123,6 @@ free_codepages_list (void) + } + } + +-#define OTHER_8BIT "Other_8_bit" +- + const char * + get_codepage_id (int n) + { +@@ -143,7 +141,7 @@ get_codepage_index (const char *id) + return -1; + } + +-static char ++char + translate_character (iconv_t cd, char c) + { + char outbuf[4], *obuf; +diff --git a/src/charsets.h b/src/charsets.h +index b701d5a..0698dc2 100644 +--- a/src/charsets.h ++++ b/src/charsets.h +@@ -6,6 +6,7 @@ + #define UNKNCHAR '\001' + + #define CHARSETS_INDEX "mc.charsets" ++#define OTHER_8BIT "Other_8_bit" + + extern int n_codepages; + +@@ -19,6 +20,10 @@ struct codepage_desc { + + extern struct codepage_desc *codepages; + ++#include ++extern char translate_character(iconv_t cd, char c); ++extern char errbuf[255]; ++ + const char *get_codepage_id (int n); + int get_codepage_index (const char *id); + int load_codepages_list (void); +diff --git a/src/cmd.c b/src/cmd.c +index f82165c..e24d563 100644 +--- a/src/cmd.c ++++ b/src/cmd.c +@@ -73,6 +73,10 @@ + # include "../edit/edit.h" + #endif + ++#ifdef HAVE_CHARSET ++#include "recode.h" ++#endif ++ + /* If set and you don't have subshell support,then C-o will give you a shell */ + int output_starts_shell = 0; + +@@ -353,6 +357,9 @@ void + mkdir_cmd (void) + { + char *dir, *absdir; ++#ifdef HAVE_CHARSET ++ char *recoded_dir; ++#endif + + dir = + input_expand_dialog (_("Create a new Directory"), +@@ -363,8 +370,16 @@ mkdir_cmd (void) + + if (dir[0] == '/' || dir[0] == '~') + absdir = g_strdup (dir); +- else ++ else { ++#ifdef HAVE_CHARSET ++ recoded_dir=g_strdup(dir); ++ my_translate_string(dir,strlen(dir), recoded_dir,current_panel->tr_table_input); ++ absdir = mhl_str_dir_plus_file (current_panel->cwd, recoded_dir); ++ g_free(recoded_dir); ++#else + absdir = mhl_str_dir_plus_file (current_panel->cwd, dir); ++#endif ++ } + + save_cwds_stat (); + if (my_mkdir (absdir, 0777) == 0) { +diff --git a/src/dialog.c b/src/dialog.c +index f8467b9..43d117f 100644 +--- a/src/dialog.c ++++ b/src/dialog.c +@@ -167,7 +167,7 @@ common_dialog_repaint (struct Dlg_head *h) + + if (h->title) { + attrset (DLG_HOT_NORMALC (h)); +- dlg_move (h, space, (h->cols - strlen (h->title)) / 2); ++ dlg_move (h, space, (h->cols - mbstrlen (h->title)) / 2); + addstr (h->title); + } + } +diff --git a/src/file.c b/src/file.c +index 6400e3e..056aa11 100644 +--- a/src/file.c ++++ b/src/file.c +@@ -79,6 +79,9 @@ + #include "../vfs/vfs-impl.h" + + /* }}} */ ++#ifdef HAVE_CHARSET ++#include "recode.h" ++#endif + + /* Hack: the vfs code should not rely on this */ + #define WITH_FULL_PATHS 1 +@@ -167,15 +170,20 @@ static const char * + do_transform_source (FileOpContext *ctx, const char *source) + { + size_t j, k, l, len; +- const char *fnsource = x_basename (source); ++ char *fnsource = g_strdup (x_basename (source)); + int next_reg; + enum CaseConvs case_conv = NO_CONV; + static char fntarget[MC_MAXPATHLEN]; + ++#ifdef UTF8 ++ fix_utf8(fnsource); ++#endif ++ + len = strlen (fnsource); + j = re_match (&ctx->rx, fnsource, len, 0, &ctx->regs); + if (j != len) { + transform_error = FILE_SKIP; ++ g_free (fnsource); + return NULL; + } + for (next_reg = 1, j = 0, k = 0; j < strlen (ctx->dest_mask); j++) { +@@ -225,6 +233,7 @@ do_transform_source (FileOpContext *ctx, const char *source) + || ctx->regs.start[next_reg] < 0) { + message (1, MSG_ERROR, _(" Invalid target mask ")); + transform_error = FILE_ABORT; ++ g_free(fnsource); + return NULL; + } + for (l = (size_t) ctx->regs.start[next_reg]; +@@ -239,6 +248,7 @@ do_transform_source (FileOpContext *ctx, const char *source) + } + } + fntarget[k] = 0; ++ g_free(fnsource); + return fntarget; + } + +@@ -922,7 +932,12 @@ copy_dir_dir (FileOpContext *ctx, const char *s, const char *d, int toplevel, + } + /* Dive into subdir if exists */ + if (toplevel && ctx->dive_into_subdirs) { ++#ifdef HAVE_CHARSET ++ /*FIXME: Use here somehow mhl_str_dir_plus_file */ ++ dest_dir = concat_dir_and_recoded_fname(d, x_basename (s), ctx); ++#else + dest_dir = mhl_str_dir_plus_file (d, x_basename (s)); ++#endif + } else { + dest_dir = g_strdup (d); + goto dont_mkdir; +@@ -972,7 +987,11 @@ copy_dir_dir (FileOpContext *ctx, const char *s, const char *d, int toplevel, + + (*ctx->stat_func) (path, &buf); + if (S_ISDIR (buf.st_mode)) { ++#ifdef HAVE_CHARSET ++ mdpath = concat_dir_and_recoded_fname(dest_dir, next->d_name, ctx); ++#else + mdpath = mhl_str_dir_plus_file (dest_dir, next->d_name); ++#endif + /* + * From here, we just intend to recursively copy subdirs, not + * the double functionality of copying different when the target +@@ -983,7 +1002,11 @@ copy_dir_dir (FileOpContext *ctx, const char *s, const char *d, int toplevel, + parent_dirs, progress_count, progress_bytes); + g_free (mdpath); + } else { ++#ifdef HAVE_CHARSET ++ dest_file=concat_dir_and_recoded_fname(dest_dir, x_basename(path),ctx); ++#else + dest_file = mhl_str_dir_plus_file (dest_dir, x_basename (path)); ++#endif + return_status = copy_file_file (ctx, path, dest_file, 1, + progress_count, progress_bytes, 0); + g_free (dest_file); +@@ -1173,7 +1196,12 @@ move_dir_dir (FileOpContext *ctx, const char *s, const char *d, + destdir = g_strdup (d); + move_over = 1; + } else ++#ifdef HAVE_CHARSET ++ destdir = concat_dir_and_recoded_fname(d, x_basename (s), ctx); ++#else + destdir = mhl_str_dir_plus_file (d, x_basename (s)); ++#endif ++ + + if (sbuf.st_dev == dbuf.st_dev && sbuf.st_ino == dbuf.st_ino) { + int msize = COLS - 36; +@@ -1700,13 +1728,13 @@ panel_operate_generate_prompt (const WPanel *panel, const int operation, + *dp = '\0'; + + if (single_source) { +- i = fmd_xlen - strlen (format_string) - 4; ++ i = fmd_xlen - mbstrlen (format_string) - 4; + g_snprintf (cmd_buf, sizeof (cmd_buf), format_string, + name_trunc (single_source, i)); + } else { + g_snprintf (cmd_buf, sizeof (cmd_buf), format_string, + panel->marked); +- i = strlen (cmd_buf) + 6 - fmd_xlen; ++ i = mbstrlen (cmd_buf) + 6 - fmd_xlen; + if (i > 0) { + fmd_xlen += i; + fmd_init_i18n (TRUE); /* to recalculate positions of child widgets */ +@@ -1901,7 +1929,12 @@ panel_operate (void *source_panel, FileOperation operation, + if (temp == NULL) { + value = transform_error; + } else { ++#ifdef HAVE_CHARSET ++ char *temp2 = concat_dir_and_recoded_fname (dest, temp, ctx); ++#else + char *temp2 = mhl_str_dir_plus_file (dest, temp); ++#endif ++ + g_free (dest); + dest = temp2; + temp = NULL; +@@ -1995,7 +2028,12 @@ panel_operate (void *source_panel, FileOperation operation, + if (temp == NULL) + value = transform_error; + else { ++#ifdef HAVE_CHARSET ++ char *temp2 = concat_dir_and_recoded_fname(dest, temp, ctx); ++#else + char *temp2 = mhl_str_dir_plus_file (dest, temp); ++#endif ++ + + source_with_path = mhl_shell_unescape_buf(source_with_path); + temp2 = mhl_shell_unescape_buf(temp2); +diff --git a/src/filegui.c b/src/filegui.c +index 441adb7..e9920d0 100644 +--- a/src/filegui.c ++++ b/src/filegui.c +@@ -66,6 +66,11 @@ + #include "filegui.h" + #include "key.h" /* get_event */ + #include "util.h" /* strip_password() */ ++#include "tty.h" ++ ++#ifdef HAVE_CHARSET ++#include "recode.h" ++#endif + + /* }}} */ + +@@ -564,8 +569,8 @@ init_replace (FileOpContext *ctx, enum OperationMode mode) + * longest of "Overwrite..." labels + * (assume "Target date..." are short enough) + */ +- l1 = max (strlen (rd_widgets[6].text), +- strlen (rd_widgets[11].text)); ++ l1 = max (mbstrlen (rd_widgets[6].text), ++ mbstrlen (rd_widgets[11].text)); + + /* longest of button rows */ + i = sizeof (rd_widgets) / sizeof (rd_widgets[0]); +@@ -576,7 +581,7 @@ init_replace (FileOpContext *ctx, enum OperationMode mode) + l2 = max (l2, l); + l = 0; + } +- l += strlen (rd_widgets[i].text) + 4; ++ l += mbstrlen (rd_widgets[i].text) + 4; + } + } + l2 = max (l2, l); /* last row */ +@@ -594,12 +599,12 @@ init_replace (FileOpContext *ctx, enum OperationMode mode) + l = l1; + } + rd_widgets[i].xpos = l; +- l += strlen (rd_widgets[i].text) + 4; ++ l += mbstrlen (rd_widgets[i].text) + 4; + } + } + /* Abort button is centered */ + rd_widgets[1].xpos = +- (rd_xlen - strlen (rd_widgets[1].text) - 3) / 2; ++ (rd_xlen - mbstrlen (rd_widgets[1].text) - 3) / 2; + } + #endif /* ENABLE_NLS */ + +@@ -618,7 +623,7 @@ init_replace (FileOpContext *ctx, enum OperationMode mode) + + ADD_RD_LABEL (ui, 0, + name_trunc (ui->replace_filename, +- rd_trunc - strlen (rd_widgets[0].text)), 0); ++ rd_trunc - mbstrlen (rd_widgets[0].text)), 0); + ADD_RD_BUTTON (1); + + ADD_RD_BUTTON (2); +@@ -721,57 +726,79 @@ file_progress_real_query_replace (FileOpContext *ctx, + } + } + ++#ifdef HAVE_CHARSET ++#define FMDY 15 ++#else + #define FMDY 13 ++#endif ++ + #define FMD_XLEN 64 + extern int fmd_xlen; + static QuickWidget fmd_widgets[] = { + +-#define FMCB0 FMDC +-#define FMCB12 0 +-#define FMCB11 1 +- /* follow symlinks and preserve Attributes must be the first */ +- {quick_checkbox, 3, 64, 8, FMDY, N_("preserve &Attributes"), 9, 0, +- 0 /* &op_preserve */ , 0, NULL}, +- {quick_checkbox, 3, 64, 7, FMDY, N_("follow &Links"), 7, 0, +- 0 /* &file_mask_op_follow_links */ , 0, NULL}, +- {quick_label, 3, 64, 5, FMDY, N_("to:"), 0, 0, 0, 0, NULL}, +- {quick_checkbox, 37, 64, 4, FMDY, N_("&Using shell patterns"), 0, 0, +- 0 /* &source_easy_patterns */ , 0, NULL}, +- {quick_input, 3, 64, 3, FMDY, "", 58, +- 0, 0, 0, "input-def"}, +-#define FMDI1 4 +-#define FMDI2 5 +-#define FMDC 3 +- {quick_input, 3, 64, 6, FMDY, "", 58, 0, +- 0, 0, "input2"}, +-#define FMDI0 6 +- {quick_label, 3, 64, 2, FMDY, "", 0, 0, 0, 0, NULL}, +-#define FMBRGT 7 +- {quick_button, 42, 64, 9, FMDY, N_("&Cancel"), 0, B_CANCEL, 0, 0, +- NULL}, +-#undef SKIP ++#ifdef HAVE_CHARSET ++ #define Y_OK 12 ++#else ++ #define Y_OK 9 ++#endif ++ + #ifdef WITH_BACKGROUND +-# define SKIP 5 +-# define FMCB21 11 +-# define FMCB22 10 +-# define FMBLFT 9 +-# define FMBMID 8 +- {quick_button, 25, 64, 9, FMDY, N_("&Background"), 0, B_USER, 0, 0, +- NULL}, +-#else /* WITH_BACKGROUND */ +-# define SKIP 4 +-# define FMCB21 10 +-# define FMCB22 9 +-# define FMBLFT 8 +-# undef FMBMID ++ #define ADD 0 ++#else ++ #define ADD -1 + #endif +- {quick_button, 14, 64, 9, FMDY, N_("&OK"), 0, B_ENTER, 0, 0, NULL}, +- {quick_checkbox, 42, 64, 8, FMDY, N_("&Stable Symlinks"), 0, 0, +- 0 /* &file_mask_stable_symlinks */ , 0, NULL}, +- {quick_checkbox, 31, 64, 7, FMDY, N_("&Dive into subdir if exists"), 0, +- 0, +- 0 /* &dive_into_subdirs */ , 0, NULL}, +- NULL_QuickWidget ++ ++ #define FM_STAB_SYM 0 ++ #define FM_DIVE_INTO_SUBDIR 1 ++ #define FM_PRES_ATTR 2 ++ #define FM_FOLLOW_LINKS 3 ++ #define FM_DST_INPUT 4 ++ #define FM_DST_TITLE 5 ++ #define FM_USING_SHELL_PATT 6 ++ #define FM_SRC_INPUT 7 ++ #define FM_SRC_TITLE 8 ++ #define FM_CANCEL 9 ++#ifdef WITH_BACKGROUND ++ #define FM_BKGND 10 ++#endif ++ #define FM_OK 11+ADD ++#ifdef HAVE_CHARSET ++ #define FM_TO_CODEPAGE 12+ADD ++ #define FM_FROM_CODEPAGE 13+ADD ++ #define FM_RECODE_TITLE 14+ADD ++ #define FM_RECODE_ARROW 15+ADD ++#endif // HAVE_CHARSET ++ ++ ++#ifdef HAVE_CHARSET ++ #define SKIP 10 ++ #define B_FROM B_USER+1 ++ #define B_TO B_USER+2 ++#else ++ #define SKIP 10 ++#endif ++ ++ {quick_checkbox, 42,64, 8, FMDY, N_("&Stable Symlinks"),0,0,0,0,"stab-sym"}, ++ {quick_checkbox, 31,64, 7, FMDY, N_("&Dive into subdir if exists"),0,0,0,0,"dive"}, ++ {quick_checkbox, 3, 64, 8, FMDY, N_("preserve &Attributes"),9,0,0,0,"preserve"}, ++ {quick_checkbox, 3, 64, 7, FMDY, N_("follow &Links"),7,0,0,0,"follow"}, ++ {quick_input, 3, 64, 6, FMDY, "", 58, 0, 0, 0, "input2"}, ++ {quick_label, 3, 64, 5, FMDY, N_("to:"), 0, 0, 0, 0, "to"}, ++ {quick_checkbox, 37,64, 4, FMDY, N_("&Using shell patterns"),0,0, 0,0,"us-sh"}, ++ {quick_input, 3, 64, 3, FMDY, "", 58, 0, 0, 0, "input-def"}, ++ {quick_label, 3, 64, 2, FMDY, "", 0, 0, 0, 0, "ql"}, ++ {quick_button, 42,64, Y_OK, FMDY, N_("&Cancel"), 0, B_CANCEL, 0,0, "cancel"}, ++#ifdef WITH_BACKGROUND ++ {quick_button, 25,64, Y_OK, FMDY, N_("&Background"), 0, B_USER, 0,0, "back"}, ++#endif ++ {quick_button, 14,64, Y_OK, FMDY, N_("&OK"), 0, B_ENTER, 0, 0, "ok"}, ++#ifdef HAVE_CHARSET ++ {quick_button, 46,64, 10, FMDY,"to codepage", 0, B_TO, 0, 0, "ql"}, ++ {quick_button, 25,64, 10, FMDY, "from codepage", 0, B_FROM, 0, 0, "ql"}, ++ {quick_label, 3, 64, 10, FMDY, N_("Recode file names:"), 0, 0, 0, 0, "ql"}, ++ {quick_label, 42,64, 10, FMDY, "->", 0, 0, 0, 0, "ql"}, ++#endif ++ {0} + }; + + static int +@@ -805,48 +832,48 @@ fmd_init_i18n (int force) + if (fmd_widgets[i].text[0] != '\0') + fmd_widgets[i].text = _(fmd_widgets[i].text); + +- len = strlen (fmd_widgets[FMCB11].text) +- + strlen (fmd_widgets[FMCB21].text) + 15; ++ len = mbstrlen (fmd_widgets[FM_FOLLOW_LINKS].text) ++ + mbstrlen (fmd_widgets[FM_DIVE_INTO_SUBDIR].text) + 15; + fmd_xlen = max (fmd_xlen, len); + +- len = strlen (fmd_widgets[FMCB12].text) +- + strlen (fmd_widgets[FMCB22].text) + 15; ++ len = mbstrlen (fmd_widgets[FM_PRES_ATTR].text) ++ + mbstrlen (fmd_widgets[FM_STAB_SYM].text) + 15; + fmd_xlen = max (fmd_xlen, len); + +- len = strlen (fmd_widgets[FMBRGT].text) +- + strlen (fmd_widgets[FMBLFT].text) + 11; ++ len = mbstrlen (fmd_widgets[FM_CANCEL].text) ++ + mbstrlen (fmd_widgets[FM_OK].text) + 11; + +-#ifdef FMBMID +- len += strlen (fmd_widgets[FMBMID].text) + 6; ++#ifdef FM_BKGND ++ len += mbstrlen (fmd_widgets[FM_BKGND].text) + 6; + #endif + + fmd_xlen = max (fmd_xlen, len + 4); + + len = (fmd_xlen - (len + 6)) / 2; +- i = fmd_widgets[FMBLFT].relative_x = len + 3; +- i += strlen (fmd_widgets[FMBLFT].text) + 8; ++ i = fmd_widgets[FM_OK].relative_x = len + 3; ++ i += mbstrlen (fmd_widgets[FM_OK].text) + 8; + +-#ifdef FMBMID +- fmd_widgets[FMBMID].relative_x = i; +- i += strlen (fmd_widgets[FMBMID].text) + 6; ++#ifdef FM_BKGND ++ fmd_widgets[FM_BKGND].relative_x = i; ++ i += mbstrlen (fmd_widgets[FM_BKGND].text) + 6; + #endif + +- fmd_widgets[FMBRGT].relative_x = i; ++ fmd_widgets[FM_CANCEL].relative_x = i; + + #define chkbox_xpos(i) \ +- fmd_widgets [i].relative_x = fmd_xlen - strlen (fmd_widgets [i].text) - 6 ++ fmd_widgets [i].relative_x = fmd_xlen - mbstrlen (fmd_widgets [i].text) - 6 + +- chkbox_xpos (FMCB0); +- chkbox_xpos (FMCB21); +- chkbox_xpos (FMCB22); ++ chkbox_xpos (FM_USING_SHELL_PATT); ++ chkbox_xpos (FM_DIVE_INTO_SUBDIR); ++ chkbox_xpos (FM_STAB_SYM); + + if (fmd_xlen != FMD_XLEN) { + i = sizeof (fmd_widgets) / sizeof (fmd_widgets[0]) - 1; + while (i--) + fmd_widgets[i].x_divisions = fmd_xlen; + +- fmd_widgets[FMDI1].hotkey_pos = +- fmd_widgets[FMDI2].hotkey_pos = fmd_xlen - 6; ++ fmd_widgets[FM_SRC_INPUT].hotkey_pos = ++ fmd_widgets[FM_DST_INPUT].hotkey_pos = fmd_xlen - 6; + } + #undef chkbox_xpos + +@@ -856,7 +883,7 @@ fmd_init_i18n (int force) + + char * + file_mask_dialog (FileOpContext *ctx, FileOperation operation, const char *text, +- const char *def_text, int only_one, int *do_background) ++ const char *def_text_orig, int only_one, int *do_background) + { + int source_easy_patterns = easy_patterns; + char *source_mask, *orig_mask, *dest_dir, *tmpdest; +@@ -865,20 +892,32 @@ file_mask_dialog (FileOpContext *ctx, FileOperation operation, const char *text, + struct stat buf; + int val; + QuickDialog Quick_input; +- ++ char *def_text; ++#ifdef HAVE_CHARSET ++ char *errmsg; ++#endif + g_return_val_if_fail (ctx != NULL, NULL); ++ ++ def_text = g_strdup(def_text_orig); ++ + #if 0 + message (1, __FUNCTION__, "text = `%s' \n def_text = `%s'", text, + def_text); + #endif ++ ++#ifdef UTF8 ++ fix_utf8(def_text); ++#endif ++ + fmd_init_i18n (FALSE); + + /* Set up the result pointers */ + +- fmd_widgets[FMCB12].result = &ctx->op_preserve; +- fmd_widgets[FMCB11].result = &ctx->follow_links; +- fmd_widgets[FMCB22].result = &ctx->stable_symlinks; +- fmd_widgets[FMCB21].result = &ctx->dive_into_subdirs; ++ fmd_widgets[FM_PRES_ATTR].result = &ctx->op_preserve; ++ fmd_widgets[FM_FOLLOW_LINKS].result = &ctx->follow_links; ++ fmd_widgets[FM_STAB_SYM].result = &ctx->stable_symlinks; ++ fmd_widgets[FM_DIVE_INTO_SUBDIR].result = &ctx->dive_into_subdirs; ++ + + /* filter out a possible password from def_text */ + def_text_secure = strip_password (g_strdup (def_text), 1); +@@ -886,8 +925,9 @@ file_mask_dialog (FileOpContext *ctx, FileOperation operation, const char *text, + /* Create the dialog */ + + ctx->stable_symlinks = 0; +- fmd_widgets[FMDC].result = &source_easy_patterns; +- fmd_widgets[FMDI1].text = easy_patterns ? "*" : "^\\(.*\\)$"; ++ fmd_widgets[FM_USING_SHELL_PATT].result = &source_easy_patterns; ++ fmd_widgets[FM_SRC_INPUT].text = easy_patterns ? "*" : "^\\(.*\\)$"; ++ + Quick_input.xlen = fmd_xlen; + Quick_input.xpos = -1; + Quick_input.title = op_names[operation]; +@@ -895,19 +935,37 @@ file_mask_dialog (FileOpContext *ctx, FileOperation operation, const char *text, + Quick_input.ylen = FMDY; + Quick_input.i18n = 1; + Quick_input.widgets = fmd_widgets; +- fmd_widgets[FMDI0].text = text; +- fmd_widgets[FMDI2].text = def_text_secure; +- fmd_widgets[FMDI2].str_result = &dest_dir; +- fmd_widgets[FMDI1].str_result = &source_mask; ++ fmd_widgets[FM_SRC_TITLE].text = text; ++ fmd_widgets[FM_DST_INPUT].text = def_text_secure; ++ fmd_widgets[FM_DST_INPUT].str_result = &dest_dir; ++ fmd_widgets[FM_SRC_INPUT].str_result = &source_mask; + + *do_background = 0; ++ ++#ifdef HAVE_CHARSET ++ ctx->from_codepage=current_panel->src_codepage; ++ ctx->to_codepage=left_panel->src_codepage; ++ if (left_panel) { ++ ctx->to_codepage=left_panel->src_codepage; ++ if( (current_panel==left_panel) && right_panel ) ctx->to_codepage=right_panel->src_codepage; ++ } ++#endif ++ + ask_file_mask: + ++#ifdef HAVE_CHARSET ++ if(operation!=OP_COPY && operation!=OP_MOVE) { ++ ctx->from_codepage=-1; ++ ctx->to_codepage=-1; ++ } ++ fmd_widgets[FM_FROM_CODEPAGE].text=get_codepage_id(ctx->from_codepage); ++ fmd_widgets[FM_TO_CODEPAGE].text=get_codepage_id(ctx->to_codepage); ++#endif ++ + if ((val = quick_dialog_skip (&Quick_input, SKIP)) == B_CANCEL) { + g_free (def_text_secure); + return 0; + } +- g_free (def_text_secure); + + if (ctx->follow_links) + ctx->stat_func = mc_stat; +@@ -929,6 +987,8 @@ file_mask_dialog (FileOpContext *ctx, FileOperation operation, const char *text, + orig_mask = source_mask; + if (!dest_dir || !*dest_dir) { + g_free (source_mask); ++ g_free (def_text_secure); ++ g_free(def_text); + return dest_dir; + } + if (source_easy_patterns) { +@@ -982,5 +1042,48 @@ file_mask_dialog (FileOpContext *ctx, FileOperation operation, const char *text, + } + if (val == B_USER) + *do_background = 1; ++#ifdef HAVE_CHARSET ++ if(val == B_FROM) { ++ if(operation==OP_COPY || operation==OP_MOVE) { ++ if(display_codepage<=0) { ++ message( 1, _(" Warning "), ++ _("To use this feature select your codepage in\n" ++ "Setup / Display Bits dialog!\n" ++ "Do not forget to save options." )); ++ goto ask_file_mask; ++ } ++ ctx->from_codepage=select_charset(ctx->from_codepage,0, ++ _(" Choose \"FROM\" codepage for COPY/MOVE operaion ")); ++ } ++ else ++ message(1,"Warning",_("Recoding works only with COPY or MOVE operation")); ++ goto ask_file_mask; ++ } ++ if(val == B_TO) { ++ if(operation==OP_COPY || operation==OP_MOVE) { ++ if(display_codepage<=0) { ++ message( 1, _(" Warning "), ++ _("To use this feature select your codepage in\n" ++ "Setup / Display Bits dialog!\n" ++ "Do not forget to save options." )); ++ goto ask_file_mask; ++ } ++ ctx->to_codepage=select_charset(ctx->to_codepage,0, ++ _(" Choose \"TO\" codepage for COPY/MOVE operaion ")); ++ } ++ else ++ message(1,"Warning",_("Recoding works only with COPY or MOVE operation")); ++ goto ask_file_mask; ++ } ++ ++ errmsg=my_init_tt(ctx->to_codepage,ctx->from_codepage,ctx->tr_table); ++ if(errmsg) { ++ my_reset_tt(ctx->tr_table,256); ++ message( 1, MSG_ERROR, "%s", errmsg); ++ } ++#endif ++ ++ g_free(def_text_secure); ++ g_free(def_text); + return dest_dir; + } +diff --git a/src/fileopctx.c b/src/fileopctx.c +index ad02cf4..904b7f8 100644 +--- a/src/fileopctx.c ++++ b/src/fileopctx.c +@@ -26,8 +26,12 @@ + #include + + #include "global.h" +-#include "fileopctx.h" + ++#ifdef HAVE_CHARSET ++#include "recode.h" ++#endif ++ ++#include "fileopctx.h" + + /** + * file_op_context_new: +@@ -54,6 +58,12 @@ file_op_context_new (FileOperation op) + ctx->umask_kill = 0777777; + ctx->erase_at_end = TRUE; + ++#ifdef HAVE_CHARSET ++ ctx->from_codepage=-1; ++ ctx->to_codepage=-1; ++ my_reset_tt(ctx->tr_table,256); ++#endif ++ + return ctx; + } + +diff --git a/src/fileopctx.h b/src/fileopctx.h +index d2de6a9..339ab42 100644 +--- a/src/fileopctx.h ++++ b/src/fileopctx.h +@@ -108,6 +108,14 @@ typedef struct FileOpContext { + /* User interface data goes here */ + + void *ui; ++ ++#ifdef HAVE_CHARSET ++ /* Recode data */ ++ int from_codepage, to_codepage; ++ unsigned char tr_table[256]; ++ unsigned char recode_buf[MC_MAXPATHLEN]; ++#endif ++ + } FileOpContext; + + +diff --git a/src/find.c b/src/find.c +index 9ff1ef7..daa1d5b 100644 +--- a/src/find.c ++++ b/src/find.c +@@ -219,7 +219,7 @@ find_parameters (char **start_dir, char **pattern, char **content) + int l1, maxlen = 0; + + while (i--) { +- l1 = strlen (labs[i] = _(labs[i])); ++ l1 = mbstrlen (labs[i] = _(labs[i])); + if (l1 > maxlen) + maxlen = l1; + } +@@ -228,7 +228,7 @@ find_parameters (char **start_dir, char **pattern, char **content) + FIND_X = i; + + for (i = sizeof (buts) / sizeof (buts[0]), l1 = 0; i--;) { +- l1 += strlen (buts[i] = _(buts[i])); ++ l1 += mbstrlen (buts[i] = _(buts[i])); + } + l1 += 21; + if (l1 > FIND_X) +@@ -237,8 +237,8 @@ find_parameters (char **start_dir, char **pattern, char **content) + ilen = FIND_X - 7 - maxlen; /* for the case of very long buttons :) */ + istart = FIND_X - 3 - ilen; + +- b1 = b0 + strlen (buts[0]) + 7; +- b2 = FIND_X - (strlen (buts[2]) + 6); ++ b1 = b0 + mbstrlen (buts[0]) + 7; ++ b2 = FIND_X - (mbstrlen (buts[2]) + 6); + + i18n_flag = 1; + case_label = _(case_label); +@@ -865,7 +865,7 @@ setup_gui (void) + if (!i18n_flag) { + register int i = sizeof (fbuts) / sizeof (fbuts[0]); + while (i--) +- fbuts[i].len = strlen (fbuts[i].text = _(fbuts[i].text)) + 3; ++ fbuts[i].len = mbstrlen (fbuts[i].text = _(fbuts[i].text)) + 3; + fbuts[2].len += 2; /* DEFPUSH_BUTTON */ + i18n_flag = 1; + } +@@ -1030,7 +1030,7 @@ find_file (char *start_dir, char *pattern, char *content, char **dirname, + + if (!next_free) /* first turn i.e clean old list */ + panel_clean_dir (current_panel); +- list->list[next_free].fnamelen = strlen (name); ++ list->list[next_free].fnamelen = mbstrlen (name); + list->list[next_free].fname = name; + list->list[next_free].f.marked = 0; + list->list[next_free].f.link_to_dir = link_to_dir; +diff --git a/src/help.c b/src/help.c +index 3261cbb..2f5bdac 100644 +--- a/src/help.c ++++ b/src/help.c +@@ -416,10 +416,28 @@ static void help_show (Dlg_head *h, const char *paint_start) + #ifndef HAVE_SLANG + addch (acs_map [c]); + #else ++#if defined(UTF8) && SLANG_VERSION < 20000 ++ SLsmg_draw_object (h->y + line + 2, h->x + col + 2, acs_map [c]); ++#else + SLsmg_draw_object (h->y + line + 2, h->x + col + 2, c); ++#endif /* UTF8 */ + #endif ++ } else { ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) { ++ int len; ++ mbstate_t mbs; ++ wchar_t wc; ++ memset (&mbs, 0, sizeof (mbs)); ++ len = mbrtowc(&wc, p, MB_CUR_MAX, &mbs); ++ if (len <= 0) len = 1; /* skip broken multibyte chars */ ++ ++ SLsmg_write_nwchars(&wc, 1); ++ p += len - 1; + } else ++#endif + addch (c); ++ } + col++; + break; + } +@@ -772,6 +790,12 @@ interactive_display (const char *filename, const char *node) + message (1, MSG_ERROR, _(" Cannot open file %s \n %s "), filename ? filename : hlpfile, + unix_error_string (errno)); + } ++ else ++ { ++ char *conv = utf8_to_local(data); ++ g_free(data); ++ data = conv; ++ } + + if (!filename) + g_free (hlpfile); +diff --git a/src/hotlist.c b/src/hotlist.c +index 737c9c1..74f9568 100644 +--- a/src/hotlist.c ++++ b/src/hotlist.c +@@ -566,7 +566,7 @@ init_i18n_stuff(int list_type, int cols) + + row = hotlist_but [i].y; + ++count [row]; +- len [row] += strlen (hotlist_but [i].text) + 5; ++ len [row] += mbstrlen (hotlist_but [i].text) + 5; + if (hotlist_but [i].flags == DEFPUSH_BUTTON) + len [row] += 2; + } +@@ -591,12 +591,12 @@ init_i18n_stuff(int list_type, int cols) + /* not first int the row */ + if (!strcmp (hotlist_but [i].text, cancel_but)) + hotlist_but [i].x = +- cols - strlen (hotlist_but [i].text) - 13; ++ cols - mbstrlen (hotlist_but [i].text) - 13; + else + hotlist_but [i].x = cur_x [row]; + } + +- cur_x [row] += strlen (hotlist_but [i].text) + 2 ++ cur_x [row] += mbstrlen (hotlist_but [i].text) + 2 + + (hotlist_but [i].flags == DEFPUSH_BUTTON ? 5 : 3); + } + } +@@ -837,7 +837,7 @@ static void add_widgets_i18n(QuickWidget* qw, int len) + for (i = 0; i < 3; i++) + { + qw [i].text = _(qw [i].text); +- l[i] = strlen (qw [i].text) + 3; ++ l[i] = mbstrlen (qw [i].text) + 3; + } + space = (len - 4 - l[0] - l[1] - l[2]) / 4; + +@@ -886,7 +886,7 @@ add_new_entry_input (const char *header, const char *text1, const char *text2, + + msglen(text1, &lines1, &cols1); + msglen(text2, &lines2, &cols2); +- len = max ((int) strlen (header), cols1); ++ len = max ((int) mbstrlen (header), cols1); + len = max (len, cols2) + 4; + len = max (len, 64); + +@@ -982,7 +982,7 @@ add_new_group_input (const char *header, const char *label, char **result) + #endif /* ENABLE_NLS */ + + msglen (label, &lines, &cols); +- len = max ((int) strlen (header), cols) + 4; ++ len = max ((int) mbstrlen (header), cols) + 4; + len = max (len, 64); + + #ifdef ENABLE_NLS +@@ -1038,7 +1038,7 @@ void add2hotlist_cmd (void) + { + char *prompt, *label; + const char *cp = _("Label for \"%s\":"); +- int l = strlen (cp); ++ int l = mbstrlen (cp); + char *label_string = g_strdup (current_panel->cwd); + + strip_password (label_string, 1); +diff --git a/src/layout.c b/src/layout.c +index 9f3616f..c759348 100644 +--- a/src/layout.c ++++ b/src/layout.c +@@ -367,36 +367,36 @@ init_layout (void) + + while (i--) { + s_split_direction[i] = _(s_split_direction[i]); +- l1 = strlen (s_split_direction[i]) + 7; ++ l1 = mbstrlen (s_split_direction[i]) + 7; + if (l1 > first_width) + first_width = l1; + } + + for (i = 0; i <= 8; i++) { + check_options[i].text = _(check_options[i].text); +- l1 = strlen (check_options[i].text) + 7; ++ l1 = mbstrlen (check_options[i].text) + 7; + if (l1 > first_width) + first_width = l1; + } + +- l1 = strlen (title1) + 1; ++ l1 = mbstrlen (title1) + 1; + if (l1 > first_width) + first_width = l1; + +- l1 = strlen (title2) + 1; ++ l1 = mbstrlen (title2) + 1; + if (l1 > first_width) + first_width = l1; + + +- second_width = strlen (title3) + 1; ++ second_width = mbstrlen (title3) + 1; + for (i = 0; i < 6; i++) { + check_options[i].text = _(check_options[i].text); +- l1 = strlen (check_options[i].text) + 7; ++ l1 = mbstrlen (check_options[i].text) + 7; + if (l1 > second_width) + second_width = l1; + } + if (console_flag) { +- l1 = strlen (output_lines_label) + 13; ++ l1 = mbstrlen (output_lines_label) + 13; + if (l1 > second_width) + second_width = l1; + } +@@ -410,14 +410,14 @@ init_layout (void) + * + * Now the last thing to do - properly space buttons... + */ +- l1 = 11 + strlen (ok_button) /* 14 - all brackets and inner space */ +- +strlen (save_button) /* notice: it is 3 char less because */ +- +strlen (cancel_button); /* of '&' char in button text */ ++ l1 = 11 + mbstrlen (ok_button) /* 14 - all brackets and inner space */ ++ +mbstrlen (save_button) /* notice: it is 3 char less because */ ++ +mbstrlen (cancel_button); /* of '&' char in button text */ + + i = (first_width + second_width - l1) / 4; + b1 = 5 + i; +- b2 = b1 + strlen (ok_button) + i + 6; +- b3 = b2 + strlen (save_button) + i + 4; ++ b2 = b1 + mbstrlen (ok_button) + i + 6; ++ b3 = b2 + mbstrlen (save_button) + i + 4; + + i18n_layt_flag = 1; + } +@@ -681,7 +681,7 @@ setup_panels (void) + panel_do_cols (0); + panel_do_cols (1); + +- promptl = strlen (prompt); ++ promptl = mbstrlen (prompt); + + widget_set_size (&the_menubar->widget, 0, 0, 1, COLS); + +diff --git a/src/learn.c b/src/learn.c +index dff560c..cc6ec93 100644 +--- a/src/learn.c ++++ b/src/learn.c +@@ -238,7 +238,7 @@ init_learn (void) + learn_but[0].x = 78 / 2 + 4; + + learn_but[1].text = _(learn_but[1].text); +- learn_but[1].x = 78 / 2 - (strlen (learn_but[1].text) + 9); ++ learn_but[1].x = 78 / 2 - (mbstrlen (learn_but[1].text) + 9); + + learn_title = _(learn_title); + i18n_flag = 1; +diff --git a/src/main.c b/src/main.c +index db26945..edf6a03 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -82,6 +82,7 @@ + + #ifdef HAVE_CHARSET + #include "charsets.h" ++#include "recode.h" + #endif /* HAVE_CHARSET */ + + #ifdef USE_VFS +@@ -98,6 +99,7 @@ + /* The structures for the panels */ + WPanel *left_panel = NULL; + WPanel *right_panel = NULL; ++WPanel* ret_panel=NULL; + + /* The pointer to the tree */ + WTree *the_tree = NULL; +@@ -276,6 +278,9 @@ int midnight_shutdown = 0; + /* The user's shell */ + const char *shell = NULL; + ++/* Is the LANG UTF-8 ? */ ++gboolean is_utf8 = FALSE; ++ + /* mc_home: The home of MC */ + char *mc_home = NULL; + +@@ -587,6 +592,7 @@ _do_panel_cd (WPanel *panel, const char *new_dir, enum cd_enum cd_type) + } + directory = *new_dir ? new_dir : home_dir; + ++ ret_panel=panel; + if (mc_chdir (directory) == -1) { + strcpy (panel->cwd, olddir); + g_free (olddir); +@@ -706,7 +712,7 @@ load_prompt (int fd, void *unused) + int prompt_len; + + tmp_prompt = strip_ctrl_codes (subshell_prompt); +- prompt_len = strlen (tmp_prompt); ++ prompt_len = mbstrlen (tmp_prompt); + + /* Check for prompts too big */ + if (COLS > 8 && prompt_len > COLS - 8) { +@@ -808,6 +814,10 @@ static menu_entry LeftMenu[] = { + {' ', N_("&Quick view C-x q"), 'Q', quick_view_cmd}, + {' ', N_("&Info C-x i"), 'I', info_cmd}, + {' ', N_("&Tree"), 'T', tree_cmd}, ++#ifdef HAVE_CHARSET ++ {' ', "", ' ', 0}, ++ {' ', N_("Panel &codepage"), 'C', fnc_l_cmd}, ++#endif + {' ', "", ' ', 0}, + {' ', N_("&Sort order..."), 'S', sort_cmd}, + {' ', "", ' ', 0}, +@@ -832,6 +842,10 @@ static menu_entry RightMenu[] = { + {' ', N_("&Quick view C-x q"), 'Q', quick_view_cmd}, + {' ', N_("&Info C-x i"), 'I', info_cmd}, + {' ', N_("&Tree"), 'T', tree_cmd}, ++#ifdef HAVE_CHARSET ++ {' ', "", ' ', 0}, ++ {' ', N_("Panel &codepage"), 'C', fnc_r_cmd}, ++#endif + {' ', "", ' ', 0}, + {' ', N_("&Sort order..."), 'S', sort_cmd}, + {' ', "", ' ', 0}, +@@ -1614,7 +1628,11 @@ update_xterm_title_path (void) + if (xterm_flag && xterm_title) { + p = s = g_strdup (strip_home_and_password (current_panel->cwd)); + do { ++#ifndef UTF8 + if (!is_printable ((unsigned char) *s)) ++#else /* UTF8 */ ++ if (*(unsigned char *)s < ' ') ++#endif /* UTF8 */ + *s = '?'; + } while (*++s); + if (!alternate_plus_minus) +@@ -2122,6 +2140,16 @@ handle_args (int argc, char *argv[]) + int + main (int argc, char *argv[]) + { ++ /* Check whether we have UTF-8 locale */ ++ char *lang = getenv("LANG"); ++ size_t len = 0; ++ ++ if ( lang ) ++ len = strlen(lang); ++ ++ if ( len >= 5 && !strcasecmp(&lang[len-5],"UTF-8") ) ++ is_utf8 = TRUE; ++ + /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */ + setlocale (LC_ALL, ""); + bindtextdomain ("mc", LOCALEDIR); +diff --git a/src/main.h b/src/main.h +index 3f3c695..fca81e7 100644 +--- a/src/main.h ++++ b/src/main.h +@@ -69,6 +69,7 @@ extern int alternate_plus_minus; + extern int only_leading_plus_minus; + extern int output_starts_shell; + extern int midnight_shutdown; ++extern gboolean is_utf8; + extern char cmd_buf [512]; + extern const char *shell; + +diff --git a/src/menu.c b/src/menu.c +index f291071..862eea8 100644 +--- a/src/menu.c ++++ b/src/menu.c +@@ -23,6 +23,7 @@ + #include + + #include ++#include + + #include "global.h" + #include "tty.h" +@@ -54,35 +55,95 @@ create_menu (const char *name, menu_entry *entries, int count, const char *help_ + { + Menu *menu; + const char *cp; ++ int wlen = 0; ++ mbstate_t s; + + menu = (Menu *) g_malloc (sizeof (*menu)); + menu->count = count; + menu->max_entry_len = 20; + menu->entries = entries; ++ menu->name = g_strdup (name); ++ menu_scan_hotkey (menu); ++#ifdef UTF8 ++ menu->wentries = NULL; ++ menu->wname = NULL; ++ if (SLsmg_Is_Unicode) { ++ const char *str = menu->name; ++ memset (&s, 0, sizeof (s)); ++ wlen = mbsrtowcs (NULL, &str, -1, &s); ++ if (wlen > 0) ++ ++wlen; ++ else { ++ wlen = 0; ++ memset (&s, 0, sizeof (s)); ++ } ++ } ++#endif + + if (entries != (menu_entry*) NULL) { + register menu_entry* mp; + for (mp = entries; count--; mp++) { + if (mp->text[0] != '\0') { ++ int len; + #ifdef ENABLE_NLS + mp->text = _(mp->text); + #endif /* ENABLE_NLS */ + cp = strchr (mp->text,'&'); ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) { ++ len = mbstrlen(mp->text) + 1; ++ wlen += len; ++ menu->max_entry_len = max (len - 1, menu->max_entry_len); ++ } else ++#endif ++ len = strlen (mp->text); + + if (cp != NULL && *(cp+1) != '\0') { + mp->hot_key = tolower ((unsigned char) *(cp+1)); +- menu->max_entry_len = max ((int) (strlen (mp->text) - 1), +- menu->max_entry_len); ++ menu->max_entry_len = max (len - 1, menu->max_entry_len); + } else { +- menu->max_entry_len = max ((int) strlen (mp->text), +- menu->max_entry_len); ++ menu->max_entry_len = max (len, menu->max_entry_len); + } + } + } + } + +- menu->name = g_strdup (name); +- menu_scan_hotkey(menu); ++#ifdef UTF8 ++ if (wlen) { ++ wchar_t *wp; ++ const char *str; ++ int len; ++ ++ menu->wentries = (wchar_t **) ++ g_malloc (sizeof (wchar_t *) * menu->count ++ + wlen * sizeof (wchar_t)); ++ wp = (wchar_t *) (menu->wentries + menu->count); ++ str = menu->name; ++ len = mbsrtowcs (wp, &str, wlen, &s); ++ if (len > 0) { ++ menu->wname = wp; ++ wlen -= len + 1; ++ wp += len + 1; ++ } else ++ memset (&s, 0, sizeof (s)); ++ if (menu->entries != NULL) ++ for (count = 0; count < menu->count; ++count) ++ if (menu->entries[count].text[0] != '\0') { ++ str = menu->entries[count].text; ++ menu->wentries[count] = wp; ++ len = mbsrtowcs (wp, &str, wlen, &s); ++ if (len > 0) { ++ wlen -= len + 1; ++ wp += len + 1; ++ } else { ++ memset (&s, 0, sizeof (s)); ++ *wp++ = L'\0'; ++ --wlen; ++ } ++ } ++ } ++#endif ++ + menu->start_x = 0; + menu->help_node = g_strdup (help_node); + return menu; +@@ -113,8 +174,26 @@ static void menubar_paint_idx (WMenu *menubar, int idx, int color) + const char *text; + + addch((unsigned char)menu->entries [idx].first_letter); +- for (text = menu->entries [idx].text; *text; text++) +- { ++#ifdef UTF8 ++ if (menu->wentries) { ++ wchar_t *wtext, *wp; ++ ++ for (wtext = wp = menu->wentries [idx]; *wtext; wtext++) { ++ if (*wtext == L'&') { ++ if (wtext > wp) ++ SLsmg_write_nwchars (wp, wtext - wp); ++ attrset (color == MENU_SELECTED_COLOR ? ++ MENU_HOTSEL_COLOR : MENU_HOT_COLOR); ++ SLsmg_write_nwchars (++wtext, 1); ++ attrset (color); ++ wp = wtext + 1; ++ } ++ } ++ if (wtext > wp) ++ SLsmg_write_nwchars (wp, wtext - wp); ++ } else ++#endif ++ for (text = menu->entries [idx].text; *text; text++) { + if (*text != '&') + addch(*text); + else { +@@ -123,7 +202,7 @@ static void menubar_paint_idx (WMenu *menubar, int idx, int color) + addch(*(++text)); + attrset(color); + } +- } ++ } + } + widget_move (&menubar->widget, y, x + 1); + } +@@ -169,6 +248,12 @@ static void menubar_draw (WMenu *menubar) + if (menubar->active) + attrset(i == menubar->selected?MENU_SELECTED_COLOR:SELECTED_COLOR); + widget_move (&menubar->widget, 0, menubar->menu [i]->start_x); ++#ifdef UTF8 ++ if (menubar->menu [i]->wname) ++ SLsmg_write_nwchars (menubar->menu [i]->wname, ++ wcslen (menubar->menu [i]->wname)); ++ else ++#endif + tty_printf ("%s", menubar->menu [i]->name); + } + +@@ -494,7 +579,13 @@ menubar_arrange(WMenu* menubar) + + for (i = 0; i < items; i++) + { +- int len = strlen(menubar->menu[i]->name); ++ int len; ++#ifdef UTF8 ++ if (menubar->menu[i]->wname) ++ len = wcslen (menubar->menu[i]->wname); ++ else ++#endif ++ len = strlen(menubar->menu[i]->name); + menubar->menu[i]->start_x = start_x; + start_x += len + gap; + } +@@ -507,7 +598,13 @@ menubar_arrange(WMenu* menubar) + for (i = 0; i < items; i++) + { + /* preserve length here, to be used below */ +- gap -= (menubar->menu[i]->start_x = strlen(menubar->menu[i]->name)); ++#ifdef UTF8 ++ if (menubar->menu[i]->wname) ++ menubar->menu[i]->start_x = wcslen (menubar->menu[i]->wname); ++ else ++#endif ++ menubar->menu[i]->start_x = strlen (menubar->menu[i]->name); ++ gap -= menubar->menu[i]->start_x; + } + + gap /= (items - 1); +@@ -531,6 +628,9 @@ menubar_arrange(WMenu* menubar) + void + destroy_menu (Menu *menu) + { ++#ifdef UTF8 ++ g_free (menu->wentries); ++#endif + g_free (menu->name); + g_free (menu->help_node); + g_free (menu); +diff --git a/src/menu.h b/src/menu.h +index e3e043e..8f52351 100644 +--- a/src/menu.h ++++ b/src/menu.h +@@ -21,6 +21,8 @@ typedef struct Menu { + menu_entry *entries; + int start_x; /* position relative to menubar start */ + char *help_node; ++ wchar_t **wentries; ++ wchar_t *wname; + } Menu; + + extern int menubar_visible; +diff --git a/src/myslang.h b/src/myslang.h +index 17057e7..774b310 100644 +--- a/src/myslang.h ++++ b/src/myslang.h +@@ -11,6 +11,16 @@ + #endif /* HAVE_SLANG_SLANG_H */ + #endif + ++#if SLANG_VERSION >= 20000 ++#define UTF8 1 ++#define SLsmg_Is_Unicode SLsmg_is_utf8_mode() ++void SLsmg_write_nwchars(wchar_t *s, size_t n); ++#endif ++ ++#ifdef UTF8 ++# include ++#endif ++ + enum { + KEY_BACKSPACE = 400, + KEY_END, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, +diff --git a/src/option.c b/src/option.c +index 2898266..b22c5f2 100644 +--- a/src/option.c ++++ b/src/option.c +@@ -124,12 +124,12 @@ init_configure (void) + title2 = _(" Pause after run... "); + title3 = _(" Other options "); + +- first_width = strlen (title1) + 1; +- second_width = strlen (title3) + 1; ++ first_width = mbstrlen (title1) + 1; ++ second_width = mbstrlen (title3) + 1; + + for (i = 0; check_options[i].text; i++) { + check_options[i].text = _(check_options[i].text); +- l1 = strlen (check_options[i].text) + 7; ++ l1 = mbstrlen (check_options[i].text) + 7; + if (i >= OTHER_OPTIONS) { + if (l1 > first_width) + first_width = l1; +@@ -142,23 +142,23 @@ init_configure (void) + i = PAUSE_OPTIONS; + while (i--) { + pause_options[i] = _(pause_options[i]); +- l1 = strlen (pause_options[i]) + 7; ++ l1 = mbstrlen (pause_options[i]) + 7; + if (l1 > first_width) + first_width = l1; + } + +- l1 = strlen (title2) + 1; ++ l1 = mbstrlen (title2) + 1; + if (l1 > first_width) + first_width = l1; + +- l1 = 11 + strlen (ok_button) +- + strlen (save_button) +- + strlen (cancel_button); ++ l1 = 11 + mbstrlen (ok_button) ++ + mbstrlen (save_button) ++ + mbstrlen (cancel_button); + + i = (first_width + second_width - l1) / 4; + b1 = 5 + i; +- b2 = b1 + strlen (ok_button) + i + 6; +- b3 = b2 + strlen (save_button) + i + 4; ++ b2 = b1 + mbstrlen (ok_button) + i + 6; ++ b3 = b2 + mbstrlen (save_button) + i + 4; + + i18n_config_flag = 1; + } +diff --git a/src/panel.h b/src/panel.h +index 844f359..05ec163 100644 +--- a/src/panel.h ++++ b/src/panel.h +@@ -72,6 +72,19 @@ typedef struct WPanel { + + int searching; + char search_buffer [256]; ++ ++#ifdef HAVE_CHARSET ++ int src_codepage; ++ unsigned char tr_table[256], tr_table_input[256]; ++#endif ++ ++#ifdef USE_VFS ++ #ifdef HAVE_CHARSET ++ int ret_codepage; ++ #endif ++ int is_return; ++ char retdir[MC_MAXPATHLEN]; ++#endif + } WPanel; + + WPanel *panel_new (const char *panel_name); +@@ -97,6 +110,7 @@ int set_panel_formats (WPanel *p); + extern WPanel *left_panel; + extern WPanel *right_panel; + extern WPanel *current_panel; ++extern WPanel* ret_panel; + + void try_to_select (WPanel *panel, const char *name); + +diff --git a/src/panelize.c b/src/panelize.c +index ef80619..d932241 100644 +--- a/src/panelize.c ++++ b/src/panelize.c +@@ -129,7 +129,7 @@ init_panelize (void) + i = sizeof (panelize_but) / sizeof (panelize_but[0]); + while (i--) { + panelize_but[i].text = _(panelize_but[i].text); +- maxlen += strlen (panelize_but[i].text) + 5; ++ maxlen += mbstrlen (panelize_but[i].text) + 5; + } + maxlen += 10; + +@@ -138,11 +138,11 @@ init_panelize (void) + panelize_cols = max (panelize_cols, maxlen); + + panelize_but[2].x = +- panelize_but[3].x + strlen (panelize_but[3].text) + 7; ++ panelize_but[3].x + mbstrlen (panelize_but[3].text) + 7; + panelize_but[1].x = +- panelize_but[2].x + strlen (panelize_but[2].text) + 5; ++ panelize_but[2].x + mbstrlen (panelize_but[2].text) + 5; + panelize_but[0].x = +- panelize_cols - strlen (panelize_but[0].text) - 8 - BX; ++ panelize_cols - mbstrlen (panelize_but[0].text) - 8 - BX; + + #endif /* ENABLE_NLS */ + +diff --git a/src/recode.c b/src/recode.c +new file mode 100644 +index 0000000..b485dfc +--- /dev/null ++++ b/src/recode.c +@@ -0,0 +1,153 @@ ++#include "recode.h" ++#ifdef HAVE_CHARSET ++ ++char *lang; ++char lang_codepage_name[256]; ++int lang_codepage; ++ ++int ftp_codepage=-1; ++ ++// recode buffer for displaying file names ++unsigned char recode_buf[MC_MAXPATHLEN]; ++ ++WPanel* recode_panel; ++ ++//--- get codepage from $LANG ++void get_locale_codepage() { ++ char* a; ++ char* b; ++ int len; ++ ++ lang=getenv("LANG"); ++ if(!lang) { ++ strncpy(lang_codepage_name,OTHER_8BIT, sizeof(OTHER_8BIT)); ++ lang_codepage=-1; ++ return; ++ } ++ ++ a=strchr(lang,'.'); ++ if(!a) { ++ strncpy(lang_codepage_name,OTHER_8BIT, sizeof(OTHER_8BIT)); ++ lang_codepage=-1; ++ return; ++ } ++ ++a; ++ ++ b=strchr(lang,'@'); ++ if(!b) b=lang+strlen(lang); ++ ++ len=b-a; ++ if(len>=sizeof(lang_codepage_name)) len=sizeof(lang_codepage_name)-1; ++ ++ memcpy(lang_codepage_name,a, len); ++ lang_codepage_name[len]='\0'; ++ lang_codepage=get_codepage_index(lang_codepage_name); ++ if(lang_codepage<0) strncpy(lang_codepage_name,OTHER_8BIT, sizeof(OTHER_8BIT)); ++} ++ ++//--- reset translation table ++void my_reset_tt(unsigned char *table,int n) { ++ int i; ++ for(i=0;isrc_codepage=-1; ++ my_reset_tt(p->tr_table,256); ++ my_reset_tt(p->tr_table_input,256); ++} ++ ++//--- Initialize translation table ++// i need this function because init_translation_table from ++// charsets.c fills only fixed translation tables conv_displ and conv_input ++//--- ++char* my_init_tt( int from, int to, unsigned char *table) { ++ int i; ++ iconv_t cd; ++ char *cpfrom, *cpto; ++ ++ if(from < 0 || to < 0 || from == to) { ++ my_reset_tt(table,256); ++ return NULL; ++ } ++ my_reset_tt(table,128); ++ cpfrom=codepages[from ].id; ++ cpto=codepages[to].id; ++ cd=iconv_open(cpfrom, cpto); ++ if(cd==(iconv_t)-1) { ++ snprintf(errbuf, 255, _("Cannot translate from %s to %s"), cpfrom, cpto); ++ return errbuf; ++ } ++ for(i=128; i<=255; ++i) table[i] = translate_character(cd, i); ++ iconv_close(cd); ++ return NULL; ++} ++ ++//--- Translate string from one codepage to another ++void my_translate_string(unsigned char *s1,int l1, unsigned char *s2, unsigned char *table) { ++ int i=0; ++ if(!s1) return; ++ while(irecode_buf,ctx->tr_table); ++ if (dir [i-1] == PATH_SEP) ++ return g_strconcat (dir, ctx->recode_buf, NULL); ++ else ++ return g_strconcat (dir, PATH_SEP_STR, ctx->recode_buf, NULL); ++ return 0; ++} ++ ++ ++//--- Internal handler for "Panel codepage" ++static void fnc_cmd(WPanel *p) { ++ char *errmsg; ++ if(display_codepage > 0) { ++ p->src_codepage=select_charset(p->src_codepage, 0, _(" Choose panel codepage ")); ++ errmsg=my_init_tt(display_codepage,p->src_codepage,p->tr_table); ++ if(errmsg) { ++ panel_reset_codepage(p); ++ message( 1, MSG_ERROR, "%s", errmsg); ++ } ++ errmsg=my_init_tt(p->src_codepage,display_codepage,p->tr_table_input); ++ if (errmsg) { ++ panel_reset_codepage(p); ++ message( 1, MSG_ERROR, "%s", errmsg ); ++ } ++ paint_dir(p); ++ show_dir(p); ++ display_mini_info(p); ++ } ++ else { ++ message( 1, _(" Warning "), ++ _("To use this feature select your codepage in\n" ++ "Setup / Display Bits dialog!\n" ++ "Do not forget to save options." )); ++ } ++} ++ ++//--- Menu handlers for "Panel codepage" for left and right panel menu ++ ++void fnc_l_cmd() { ++ fnc_cmd(left_panel); ++} ++ ++void fnc_r_cmd() { ++ fnc_cmd(right_panel); ++} ++ ++//--- screen handler for "Panel codepage" ++void fnc_c_cmd(WPanel *panel) { ++ fnc_cmd(current_panel); ++} ++ ++#endif //HAVE_CHARSET +diff --git a/src/recode.h b/src/recode.h +new file mode 100644 +index 0000000..8e817ea +--- /dev/null ++++ b/src/recode.h +@@ -0,0 +1,48 @@ ++#ifndef __RECODE_H__ ++#define __RECODE_H__ ++#include ++#ifdef HAVE_CHARSET ++ ++#include ++#include ++#include ++ ++#include "global.h" ++#include "wtools.h" ++#include "panel.h" ++#include "charsets.h" ++#include "selcodepage.h" ++#include "screen.h" ++#include "main.h" ++#include "fileopctx.h" ++ ++extern char *lang; ++extern char lang_codepage_name[256]; ++extern int lang_codepage; ++ ++extern int ftp_codepage; ++ ++// recode buffer for displaying file names ++extern unsigned char recode_buf[MC_MAXPATHLEN]; ++extern WPanel* recode_panel; ++ ++//--- get codepage from $LANG ++extern void get_locale_codepage(); ++ ++//--- reset translation table ++extern void my_reset_tt(unsigned char *table,int n); ++//--- reset panel codepage ++extern void panel_reset_codepage(WPanel *p); ++//--- Initialize translation table ++extern char* my_init_tt( int from, int to, unsigned char *table); ++//--- Translate string from one codepage to another ++extern void my_translate_string(unsigned char *s1,int l1, unsigned char *s2, unsigned char *table); ++//--- Recode filename and concat in to dir ++extern char* concat_dir_and_recoded_fname(const char *dir, const char *fname, FileOpContext *ctx); ++//--- handlers for "Panel codepage" ++extern void fnc_l_cmd(); ++extern void fnc_r_cmd(); ++extern void fnc_c_cmd(WPanel *panel); ++ ++#endif // HAVE_CHARSET ++#endif //__RECODE_H__ +diff --git a/src/screen.c b/src/screen.c +index 6c3821b..1f938bc 100644 +--- a/src/screen.c ++++ b/src/screen.c +@@ -52,6 +52,10 @@ + #include "main.h" /* the_menubar */ + #include "unixcompat.h" + ++#ifdef HAVE_CHARSET ++#include "recode.h" ++#endif ++ + #define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) ) + + #define J_LEFT 1 +@@ -173,21 +177,64 @@ add_permission_string (char *dest, int width, file_entry *fe, int attr, int colo + static const char * + string_file_name (file_entry *fe, int len) + { +- static char buffer [MC_MAXPATHLEN + 1]; + size_t i; ++ char* filename; + +- for (i = 0; i < sizeof(buffer) - 1; i++) { +- char c; ++#ifdef UTF8 ++ static char buffer [BUF_SMALL * 4]; ++ mbstate_t s; ++ int mbmax = MB_CUR_MAX; ++ const char *str = fe->fname; + +- c = fe->fname[i]; ++ memset (&s, 0, sizeof (s)); ++#else ++ static char buffer [BUF_SMALL]; ++#endif + +- if (!c) +- break; ++#ifdef HAVE_CHARSET ++ my_translate_string(fe->fname,fe->fnamelen, recode_buf, recode_panel->tr_table); ++ filename= recode_buf; ++#else ++ filename=fe->fname; ++#endif + +- if (!is_printable(c)) +- c = '?'; ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) ++ for (i = 0; i < sizeof (buffer) - 1; i++) { ++ wchar_t wc; ++ int len; + +- buffer[i] = c; ++ len = mbrtowc (&wc, str, mbmax, &s); ++ if (!len) ++ break; ++ if (len < 0) { ++ memset (&s, 0, sizeof (s)); ++ buffer[i] = '?'; ++ str++; ++ continue; ++ } ++ if (!is_printable (wc)) { ++ buffer[i] = '?'; ++ str++; ++ continue; ++ } ++ if (i >= sizeof (buffer) - len) ++ break; ++ memcpy (buffer + i, str, len); ++ i += len - 1; ++ str += len; ++ } else ++#endif ++ for (i = 0; i < sizeof(buffer) - 1; i++) { ++ char c; ++ ++ c = filename[i]; ++ ++ if (!c) break; ++ ++ if (!is_printable(c)) c = '?'; ++ ++ buffer[i] = c; + } + + buffer[i] = 0; +@@ -452,42 +499,6 @@ static struct { + { "dot", 1, 0, J_RIGHT, " ", 0, string_dot, NULL }, + }; + +-static char * +-to_buffer (char *dest, int just_mode, int len, const char *txt) +-{ +- int txtlen = strlen (txt); +- int still, over; +- +- /* Fill buffer with spaces */ +- memset (dest, ' ', len); +- +- still = (over=(txtlen > len)) ? (txtlen - len) : (len - txtlen); +- +- switch (HIDE_FIT(just_mode)){ +- case J_LEFT: +- still = 0; +- break; +- case J_CENTER: +- still /= 2; +- break; +- case J_RIGHT: +- default: +- break; +- } +- +- if (over){ +- if (IS_FIT(just_mode)) +- strcpy (dest, name_trunc(txt, len)); +- else +- strncpy (dest, txt+still, len); +- } else +- strncpy (dest+still, txt, txtlen); +- +- dest[len] = '\0'; +- +- return (dest + len); +-} +- + static int + file_compute_color (int attr, file_entry *fe) + { +@@ -541,14 +552,18 @@ file_compute_color (int attr, file_entry *fe) + + /* Formats the file number file_index of panel in the buffer dest */ + static void +-format_file (char *dest, int limit, WPanel *panel, int file_index, int width, int attr, int isstatus) ++format_file (WPanel *panel, int file_index, int width, int attr, int isstatus) + { + int color, length, empty_line; + const char *txt; +- char *old_pos; +- char *cdest = dest; + format_e *format, *home; + file_entry *fe; ++#ifdef UTF8 ++ char buffer[BUF_MEDIUM * sizeof (wchar_t)]; ++#else ++ char buffer[BUF_MEDIUM]; ++#endif ++ int txtwidth = 0; + + length = 0; + empty_line = (file_index >= panel->count); +@@ -566,34 +581,137 @@ format_file (char *dest, int limit, WPanel *panel, int file_index, int width, in + break; + + if (format->string_fn){ +- int len; ++ int len, still, over, perm, txtlen, wide; + + if (empty_line) + txt = " "; + else + txt = (*format->string_fn)(fe, format->field_len); + +- old_pos = cdest; +- + len = format->field_len; + if (len + length > width) + len = width - length; +- if (len + (cdest - dest) > limit) +- len = limit - (cdest - dest); ++ if (len >= BUF_MEDIUM) ++ len = BUF_MEDIUM - 1; + if (len <= 0) + break; +- cdest = to_buffer (cdest, format->just_mode, len, txt); +- length += len; + +- attrset (color); ++ perm = 0; ++ if (permission_mode) { ++ if (!strcmp(format->id, "perm")) ++ perm = 1; ++ else if (!strcmp(format->id, "mode")) ++ perm = 2; ++ } + +- if (permission_mode && !strcmp(format->id, "perm")) +- add_permission_string (old_pos, format->field_len, fe, attr, color, 0); +- else if (permission_mode && !strcmp(format->id, "mode")) +- add_permission_string (old_pos, format->field_len, fe, attr, color, 1); +- else +- addstr (old_pos); ++ wide = 0; ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode && !empty_line && !perm) { ++ mbstate_t s; ++ const char *str = txt; ++ ++ memset (&s, 0, sizeof (s)); ++ txtlen = mbsrtowcs ((wchar_t *) buffer, &str, ++ sizeof (buffer) / sizeof (wchar_t), &s); ++ if (txtlen < 0) { ++ txt = " "; ++ txtlen = 1; ++ } else { ++ wide = 1; ++ txtwidth = wcswidth((wchar_t*)buffer, txtlen); ++ } ++ } else ++#endif ++ { ++ txtlen = mbstrlen (txt); ++ txtwidth = txtlen; ++ } ++ ++ over = txtwidth > len; ++ still = over ? txtlen - len : len - txtlen; ++ ++ switch (HIDE_FIT(format->just_mode)) { ++ case J_LEFT: ++ still = 0; ++ break; ++ case J_CENTER: ++ still /= 2; ++ break; ++ case J_RIGHT: ++ default: ++ break; ++ } ++ ++ attrset (color); ++ ++ if (wide) { ++#ifdef UTF8 ++ if (over) { ++ if (IS_FIT (format->just_mode)) { ++ int n1 = 0; ++ int width1 = 0; ++ int n2 = 0; ++ int width2 = 0; ++ int len1 = len / 2; ++ int len2; ++ ++ while (1) { ++ int w = wcwidth(((wchar_t *) buffer)[n1]); ++ if (width1 + w <= len1) { ++ width1 += w; ++ n1++; ++ } ++ else ++ break; ++ } ++ len2 = len - width1 - 1; ++ ++ while (1) { ++ int w = wcwidth(((wchar_t *) buffer)[txtlen - n2 - 1]); ++ if (width2 + w <= len2) { ++ width2 += w; ++ n2++; ++ } ++ else ++ break; ++ } ++ ++ ++ SLsmg_write_nwchars ((wchar_t *) buffer, n1); ++ SLsmg_write_nwchars (L"~", 1); ++ printw ("%*s", len - width1 - width2 - 1, ""); ++ SLsmg_write_nwchars (((wchar_t *) buffer) ++ + txtlen - n2, n2); ++ } else ++ SLsmg_write_nwchars ((wchar_t *) buffer + still, len); ++ } else { ++ printw ("%*s", still, ""); ++ SLsmg_write_nwchars ((wchar_t *) buffer, txtlen); ++ printw ("%*s", len - txtwidth - still, ""); ++ } ++#endif ++ } else { ++ if (over) { ++ if (IS_FIT (format->just_mode)) ++ strcpy (buffer, name_trunc(txt, len)); ++ else ++ memcpy (buffer, txt + still, len); ++ } else { ++ memset (buffer, ' ', still); ++ memcpy (buffer + still, txt, txtlen); ++ memset (buffer + still + txtlen, ' ', ++ len - txtlen - still); ++ } ++ buffer[len] = '\0'; ++ ++ if (perm) ++ add_permission_string (buffer, format->field_len, fe, ++ attr, color, perm - 1); ++ else ++ addstr (buffer); ++ } + ++ length += len; + } else { + if (attr == SELECTED || attr == MARKED_SELECTED) + attrset (SELECTED_COLOR); +@@ -616,7 +734,10 @@ repaint_file (WPanel *panel, int file_index, int mv, int attr, int isstatus) + { + int second_column = 0; + int width, offset; +- char buffer [BUF_MEDIUM]; ++ ++#ifdef HAVE_CHARSET ++ recode_panel=panel; ++#endif + + offset = 0; + if (!isstatus && panel->split){ +@@ -645,7 +766,7 @@ repaint_file (WPanel *panel, int file_index, int mv, int attr, int isstatus) + widget_move (&panel->widget, file_index - panel->top_file + 2, 1); + } + +- format_file (buffer, sizeof(buffer), panel, file_index, width, attr, isstatus); ++ format_file (panel, file_index, width, attr, isstatus); + + if (!isstatus && panel->split){ + if (second_column) +@@ -657,7 +778,7 @@ repaint_file (WPanel *panel, int file_index, int mv, int attr, int isstatus) + } + } + +-static void ++void + display_mini_info (WPanel *panel) + { + if (!show_mini_info) +@@ -694,7 +815,7 @@ display_mini_info (WPanel *panel) + ngettext("%s in %d file", "%s in %d files", panel->marked), + b_bytes, panel->marked); + +- if ((int) strlen (buffer) > cols-2){ ++ if ((int) mbstrlen (buffer) > cols-2){ + buffer [cols] = 0; + p += 2; + } else +@@ -727,7 +848,7 @@ display_mini_info (WPanel *panel) + return; + } + +-static void ++void + paint_dir (WPanel *panel) + { + int i; +@@ -765,7 +886,7 @@ mini_info_separator (WPanel *panel) + #endif /* !HAVE_SLANG */ + } + +-static void ++void + show_dir (WPanel *panel) + { + char *tmp; +@@ -785,6 +906,9 @@ show_dir (WPanel *panel) + } + #endif /* HAVE_SLANG */ + ++ vscrollbar (panel->widget, panel->widget.lines, panel->widget.cols-1, 2, 2, ++ panel->selected, panel->count, TRUE); ++ + if (panel->active) + attrset (REVERSE_COLOR); + +@@ -794,8 +918,15 @@ show_dir (WPanel *panel) + tmp = g_malloc (panel->widget.cols + 1); + tmp[panel->widget.cols] = '\0'; + ++#ifdef HAVE_CHARSET ++ my_translate_string(panel->cwd,strlen(panel->cwd),recode_buf, panel->tr_table); ++ trim (strip_home_and_password (recode_buf), tmp, ++ min (max (panel->widget.cols - 7, 0), panel->widget.cols) ); ++ #else + trim (strip_home_and_password (panel->cwd), tmp, + max (panel->widget.cols - 9, 0)); ++#endif ++ + addstr (tmp); + g_free (tmp); + +@@ -1008,6 +1139,17 @@ panel_new (const char *panel_name) + mc_get_current_wd (panel->cwd, sizeof (panel->cwd) - 2); + strcpy (panel->lwd, "."); + ++#ifdef HAVE_CHARSET ++ panel_reset_codepage(panel); ++#endif ++ ++#ifdef USE_VFS ++ panel->is_return=0; ++ #ifdef HAVE_CHARSET ++ panel->ret_codepage=-1; ++ #endif ++#endif ++ + panel->hist_name = g_strconcat ("Dir Hist ", panel_name, (char *) NULL); + panel->dir_history = history_get (panel->hist_name); + directory_history_add (panel, panel->cwd); +@@ -1107,6 +1249,12 @@ paint_frame (WPanel *panel) + int side, width; + + const char *txt; ++#ifdef UTF8 ++ char buffer[30 * sizeof (wchar_t)]; ++ mbstate_t s; ++ ++ memset (&s, 0, sizeof (s)); ++#endif + if (!panel->split) + adjust_top_file (panel); + +@@ -1131,16 +1279,38 @@ paint_frame (WPanel *panel) + if (format->string_fn){ + txt = format->title; + +- header_len = strlen (txt); ++ attrset (MARKED_COLOR); ++ width -= format->field_len; ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) { ++ const char *str = txt; ++ header_len = mbsrtowcs ((wchar_t *) buffer, &str, ++ sizeof (buffer) / sizeof (wchar_t), ++ &s); ++ if (header_len < 0) { ++ memset (&s, 0, sizeof (s)); ++ printw ("%*s", format->field_len, ""); ++ continue; ++ } ++ if (header_len > format->field_len) ++ header_len = format->field_len; ++ spaces = (format->field_len - header_len) / 2; ++ extra = (format->field_len - header_len) % 2; ++ printw ("%*s", spaces, ""); ++ SLsmg_write_nwchars ((wchar_t *) buffer, header_len); ++ printw ("%*s", spaces + extra, ""); ++ continue; ++ } ++#endif ++ ++ header_len = mbstrlen (txt); + if (header_len > format->field_len) + header_len = format->field_len; + +- attrset (MARKED_COLOR); + spaces = (format->field_len - header_len) / 2; + extra = (format->field_len - header_len) % 2; + tty_printf ("%*s%.*s%*s", spaces, "", + header_len, txt, spaces+extra, ""); +- width -= 2 * spaces + extra + header_len; + } else { + attrset (NORMAL_COLOR); + one_vline (); +@@ -1358,7 +1528,7 @@ use_display_format (WPanel *panel, const char *format, char **error, int isstatu + panel->dirty = 1; + + /* Status needn't to be split */ +- usable_columns = ((panel->widget.cols-2)/((isstatus) ++ usable_columns = ((panel->widget.cols-3)/((isstatus) + ? 1 + : (panel->split+1))) - (!isstatus && panel->split); + +@@ -1897,11 +2067,24 @@ do_search (WPanel *panel, int c_code) + int i; + int wrapped = 0; + int found; ++ int prevpos, pos; ++ int j; ++ mbstate_t mbs; + + l = strlen (panel->search_buffer); + if (c_code == KEY_BACKSPACE) { +- if (l) +- panel->search_buffer[--l] = '\0'; ++ if (l) { ++ prevpos = pos = 0; ++ memset (&mbs, 0, sizeof (mbs)); ++ while (pos < l) { ++ prevpos = pos; ++ j = mbrlen (panel->search_buffer + pos, l - pos, &mbs); ++ if (j <= 0) break; ++ pos += j; ++ } ++ --l; ++ panel->search_buffer[prevpos] = 0; ++ } + } else { + if (c_code && l < sizeof (panel->search_buffer)) { + panel->search_buffer[l] = c_code; +@@ -1910,6 +2093,14 @@ do_search (WPanel *panel, int c_code) + } + } + ++ prevpos = pos = 0; ++ memset (&mbs, 0, sizeof (mbs)); ++ while (pos < l) { ++ prevpos = pos; ++ j = mbrlen (panel->search_buffer + pos, l - pos, &mbs); ++ if (j <= 0) break; ++ pos += j; ++ } + found = 0; + for (i = panel->selected; !wrapped || i != panel->selected; i++) { + if (i >= panel->count) { +@@ -1920,9 +2111,9 @@ do_search (WPanel *panel, int c_code) + } + if (panel-> + case_sensitive +- ? (strncmp (panel->dir.list[i].fname, panel->search_buffer, l) ++ ? (strncmp (panel->dir.list[i].fname, panel->search_buffer, pos) + == 0) : (g_strncasecmp (panel->dir.list[i].fname, +- panel->search_buffer, l) == 0)) { ++ panel->search_buffer, pos) == 0)) { + unselect_item (panel); + panel->selected = i; + select_item (panel); +@@ -1931,7 +2122,7 @@ do_search (WPanel *panel, int c_code) + } + } + if (!found) +- panel->search_buffer[--l] = 0; ++ panel->search_buffer[prevpos] = 0; + + paint_panel (panel); + } +@@ -2160,7 +2351,12 @@ static const panel_key_map panel_keymap [] = { + { XCTRL('n'), move_down }, /* C-n like emacs */ + { XCTRL('s'), start_search }, /* C-s like emacs */ + { ALT('s'), start_search }, /* M-s not like emacs */ ++#ifndef HAVE_CHARSET + { XCTRL('t'), mark_file }, ++#endif ++#ifdef HAVE_CHARSET ++ { XCTRL('t'), mark_file }, /* was 'fnc_c_cmd' */ ++#endif + { ALT('o'), chdir_other_panel }, + { ALT('i'), sync_other_panel }, + { ALT('l'), chdir_to_readlink }, +diff --git a/src/screen.h b/src/screen.h +new file mode 100644 +index 0000000..4efb525 +--- /dev/null ++++ b/src/screen.h +@@ -0,0 +1,11 @@ ++#ifndef __SCREEN_H__ ++#define __SCREEN_H__ ++#include ++ ++#include "global.h" ++ ++extern void paint_dir (WPanel *panel); ++extern void display_mini_info (WPanel *panel); ++extern void show_dir(WPanel *panel); ++#endif //__SCREEN_H__ ++ +diff --git a/src/selcodepage.c b/src/selcodepage.c +index 3e9ec63..dabed0e 100644 +--- a/src/selcodepage.c ++++ b/src/selcodepage.c +@@ -45,14 +45,16 @@ get_hotkey (int n) + } + + int +-select_charset (int current_charset, int seldisplay) ++select_charset (int current_charset, int seldisplay, const char *title) + { ++ int new_charset; ++ + int i, menu_lines = n_codepages + 1; + char buffer[255]; + + /* Create listbox */ + Listbox *listbox = create_listbox_window (ENTRY_LEN + 2, menu_lines, +- _(" Choose input codepage "), ++ title, + "[Codepages Translation]"); + + if (!seldisplay) +@@ -82,20 +84,26 @@ select_charset (int current_charset, int seldisplay) + + i = run_listbox (listbox); + +- return (seldisplay) ? ((i >= n_codepages) ? -1 : i) +- : (i - 1); ++ if(i==-1) ++ i = (seldisplay) ++ ? ((current_charset < 0) ? n_codepages : current_charset) ++ : (current_charset + 1); ++ ++ new_charset =(seldisplay) ? ( (i >= n_codepages) ? -1 : i ) : ( i-1 ); ++ new_charset = (new_charset==-2) ? current_charset:new_charset; ++ return new_charset; + } + + /* Helper functions for codepages support */ + + + int +-do_select_codepage (void) ++do_select_codepage (const char *title) + { + const char *errmsg; + + if (display_codepage > 0) { +- source_codepage = select_charset (source_codepage, 0); ++ source_codepage = select_charset (source_codepage, 0, title); + errmsg = + init_translation_table (source_codepage, display_codepage); + if (errmsg) { +diff --git a/src/selcodepage.h b/src/selcodepage.h +index 06fbd77..f7f16de 100644 +--- a/src/selcodepage.h ++++ b/src/selcodepage.h +@@ -2,8 +2,8 @@ + #define MC_SELCODEPAGE_H + + #ifdef HAVE_CHARSET +-int select_charset (int current_charset, int seldisplay); +-int do_select_codepage (void); ++int select_charset (int current_charset, int seldisplay, const char *title); ++int do_select_codepage (const char *title); + #endif /* HAVE_CHARSET */ + + #endif +diff --git a/src/setup.c b/src/setup.c +index 67dec4a..4c78e5b 100644 +--- a/src/setup.c ++++ b/src/setup.c +@@ -50,6 +50,8 @@ + + #ifdef HAVE_CHARSET + #include "charsets.h" ++#include"recode.h" ++#include "wtools.h" + #endif + + #ifdef USE_NETCODE +@@ -273,6 +275,11 @@ panel_save_setup (struct WPanel *panel, const char *section) + g_snprintf (buffer, sizeof (buffer), "%d", panel->user_mini_status); + save_string (section, "user_mini_status", buffer, + profile_name); ++ ++#ifdef HAVE_CHARSET ++ // save panel codepage ++ save_string(section, "panel_display_codepage", get_codepage_id(panel->src_codepage), profile_name); ++#endif + } + + void +@@ -375,6 +382,7 @@ save_setup (void) + #ifdef HAVE_CHARSET + save_string( "Misc", "display_codepage", + get_codepage_id( display_codepage ), profile_name ); ++ save_string( "Misc", "ftp_codepage", get_codepage_id(ftp_codepage), profile_name); + #endif /* HAVE_CHARSET */ + + g_free (profile); +@@ -425,6 +433,31 @@ panel_load_setup (WPanel *panel, const char *section) + panel->user_mini_status = + load_int (section, "user_mini_status", 0); + ++#ifdef HAVE_CHARSET ++//--- Loading panel codepage ++ panel_reset_codepage(panel); ++ if(load_codepages_list()>0) { ++ char cpname[128]; ++ char *errmsg; ++ ++ ++ if(display_codepage>=0) { ++ load_string(section, "panel_display_codepage", "", cpname, sizeof(cpname)); ++ if(cpname[0]!='\0') panel->src_codepage = get_codepage_index(cpname); ++ } ++ ++ errmsg=my_init_tt(display_codepage,panel->src_codepage,panel->tr_table); ++ if(errmsg) { ++ panel_reset_codepage(panel); ++ message( 1, MSG_ERROR, "%s", errmsg ); ++ } ++ errmsg=my_init_tt(panel->src_codepage,display_codepage,panel->tr_table_input); ++ if(errmsg) { ++ panel_reset_codepage(panel); ++ message( 1, MSG_ERROR, "%s", errmsg ); ++ } ++ } ++#endif + } + + static void +@@ -574,10 +607,16 @@ load_setup (void) + #ifdef HAVE_CHARSET + if ( load_codepages_list() > 0 ) { + char cpname[128]; +- load_string( "Misc", "display_codepage", "", +- cpname, sizeof(cpname) ); +- if ( cpname[0] != '\0' ) +- display_codepage = get_codepage_index( cpname ); ++ get_locale_codepage(); ++ load_string("Misc", "display_codepage", "", cpname, sizeof(cpname)); ++ if(cpname[0] != '\0') display_codepage=get_codepage_index(cpname); ++ else display_codepage=lang_codepage; ++ ++ ftp_codepage=-1; ++ if(display_codepage >= 0) { ++ load_string( "Misc", "ftp_codepage", "", cpname, sizeof(cpname)); ++ if(cpname[0] != '\0') ftp_codepage=get_codepage_index(cpname); ++ } + } + + init_translation_table( source_codepage, display_codepage ); +diff --git a/src/slint.c b/src/slint.c +index c30fac1..88557ac 100644 +--- a/src/slint.c ++++ b/src/slint.c +@@ -142,7 +142,9 @@ void + slang_init (void) + { + SLtt_get_terminfo (); +- ++#if SLANG_VERSION >= 20000 ++ SLutf8_enable (-1); ++#endif + /* + * If the terminal in not in terminfo but begins with a well-known + * string such as "linux" or "xterm" S-Lang will go on, but the +diff --git a/src/timefmt.h b/src/timefmt.h +index 2b8d52f..2cf4a38 100644 +--- a/src/timefmt.h ++++ b/src/timefmt.h +@@ -19,7 +19,7 @@ + } \ + else \ + { \ +- strftime(buffer, bufsize, fmt, whentm); \ ++ strftime(buffer, bufsize -1, fmt, whentm); \ + } \ + } \ + +diff --git a/src/tty.c b/src/tty.c +index a71c6cc..961132b 100644 +--- a/src/tty.c ++++ b/src/tty.c +@@ -134,10 +134,12 @@ tty_print_char(int c) + * defined or not. Congratulations! At least, they left the API call + * for SLsmg_write_nchars as it has always been. + */ +- char ch; + +- ch = c; +- SLsmg_write_nchars(&ch, 1); ++ /* The above comment is a nonsense, SLsmg_write_char(c) works pretty ++ * good for me. So please don't mess with Red Hat people. ++ * Jindrich Novy (jnovy@redhat.com) ++ */ ++ SLsmg_write_nwchars(&c, 1); + #else + addch(c); + #endif +diff --git a/src/tty.h b/src/tty.h +index 85d286b..d27e639 100644 +--- a/src/tty.h ++++ b/src/tty.h +@@ -8,6 +8,8 @@ + of ifdefs in the other files small. + */ + ++#include /* gboolean is used here */ ++ + #ifdef HAVE_SLANG + # include "myslang.h" + #endif +diff --git a/src/util.c b/src/util.c +index 35658b0..5f87b57 100644 +--- a/src/util.c ++++ b/src/util.c +@@ -34,10 +34,14 @@ + #include + #include + #include ++#include ++#include ++#include + + #include + #include + ++#include "tty.h" + #include "global.h" + #include "profile.h" + #include "main.h" /* mc_home */ +@@ -50,9 +54,39 @@ + #include "charsets.h" + #endif + ++#ifdef UTF8 ++#include ++#endif ++ + static const char app_text [] = "Midnight-Commander"; + int easy_patterns = 1; + ++#if SLANG_VERSION >= 20000 ++void SLsmg_write_nwchars(wchar_t *s, size_t n) ++{ ++ if (SLsmg_is_utf8_mode()) { /* slang can handle it directly */ ++ while(n-- && *s) ++ SLsmg_write_char(*s++); ++ } ++ else { /* convert wchars back to 8bit encoding */ ++ mbstate_t mbs; ++ memset (&mbs, 0, sizeof (mbs)); ++ while (n-- && *s) { ++ char buf[MB_LEN_MAX + 1]; /* should use 1 char, but to be sure */ ++ if (*s < 0x80) { ++ SLsmg_write_char(*s++); /* ASCII */ ++ } ++ else { ++ if (wcrtomb(buf, *s++, &mbs) == 1) ++ SLsmg_write_char((wchar_t)(buf[0])); ++ else ++ SLsmg_write_char('?'); /* should not happen */ ++ } ++ } ++ } ++} ++#endif ++ + extern void str_replace(char *s, char from, char to) + { + for (; *s != '\0'; s++) { +@@ -83,9 +117,106 @@ is_8bit_printable (unsigned char c) + return (c > 31 && c != 127 && c != 155); + } + ++size_t ++mbstrlen (const char *str) ++{ ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) { ++ size_t width = 0; ++ ++ for (; *str; str++) { ++ wchar_t c; ++ size_t len; ++ ++ len = mbrtowc (&c, str, MB_CUR_MAX, NULL); ++ ++ if (len == (size_t)(-1) || len == (size_t)(-2)) break; ++ ++ if (len > 0) { ++ int wcsize = wcwidth(c); ++ width += wcsize > 0 ? wcsize : 0; ++ str += len-1; ++ } ++ } ++ ++ return width; ++ } else ++#endif ++ return strlen (str); ++} ++ ++#ifdef UTF8 ++ ++void ++fix_utf8(char *str) ++{ ++ mbstate_t mbs; ++ ++ char *p = str; ++ ++ while (*p) { ++ int len; ++ memset (&mbs, 0, sizeof (mbs)); ++ len = mbrlen(p, MB_CUR_MAX, &mbs); ++ if (len == -1) { ++ *p = '?'; ++ p++; ++ } else if (len > 0) { ++ p += len; ++ } else { ++ p++; ++ } ++ } ++} ++#endif ++ ++ ++ ++#ifdef UTF8 ++wchar_t * ++mbstr_to_wchar (const char *str) ++{ ++ int len = mbstrlen(str); ++ wchar_t *buf = g_malloc((len+1) * sizeof(wchar_t)); ++ mbstate_t mbs; ++ memset (&mbs, 0, sizeof (mbs)); ++ mbsrtowcs (buf, &str, len, &mbs); ++ buf[len] = 0; ++ return buf; ++} ++ ++char * ++wchar_to_mbstr (const wchar_t *wstr) ++{ ++ mbstate_t mbs; ++ const wchar_t *wstr2; ++ char * string; ++ int len; ++ ++ memset (&mbs, 0, sizeof (mbs)); ++ wstr2 = wstr; ++ len = wcsrtombs(NULL, &wstr2, 0, &mbs); ++ if (len <= 0) ++ return NULL; ++ ++ string = g_malloc(len + 1); ++ ++ wstr2 = wstr; ++ wcsrtombs(string, &wstr2, len, &mbs); ++ string[len] = 0; ++ return string; ++} ++#endif ++ ++ ++ + int + is_printable (int c) + { ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) ++ return iswprint (c); ++#endif + c &= 0xff; + + #ifdef HAVE_CHARSET +@@ -103,7 +234,7 @@ is_printable (int c) + #endif /* !HAVE_CHARSET */ + } + +-/* Calculates the message dimensions (lines and columns) */ ++/* Calculates the message dimension in columns and lines. */ + void + msglen (const char *text, int *lines, int *columns) + { +@@ -116,8 +247,21 @@ msglen (const char *text, int *lines, int *columns) + nlines++; + colindex = 0; + } else { ++#ifndef UTF8 + colindex++; + if (colindex > ncolumns) ++#else /* UTF8 */ ++ size_t len; ++ wchar_t c; ++ ++ len = mbrtowc (&c, text, MB_CUR_MAX, NULL); ++ if (len > 0 && len != (size_t)(-1) && len != (size_t)(-2)) { ++ int wcsize = wcwidth(c); ++ colindex += wcsize > 0 ? wcsize-1 : -1; ++ text += len-1; ++ } ++ if (++colindex > ncolumns) ++#endif /* UTF8 */ + ncolumns = colindex; + } + } +@@ -211,7 +355,24 @@ name_quote (const char *s, int quote_percent) + *d++ = '\\'; + break; + } ++#ifndef UTF8 + *d = *s; ++#else /* UTF8 */ ++ { ++ mbstate_t mbs; ++ int len; ++ memset (&mbs, 0, sizeof (mbs)); ++ len = mbrlen(s, MB_CUR_MAX, &mbs); ++ if (len > 0) { ++ while (len-- > 1) ++ *d++ = *s++; ++ *d = *s; ++ } else { ++ *d = '?'; ++ } ++ ++ } ++#endif /* UTF8 */ + } + *d = '\0'; + return ret; +@@ -233,25 +394,90 @@ const char * + name_trunc (const char *txt, int trunc_len) + { + static char x[MC_MAXPATHLEN + MC_MAXPATHLEN]; +- int txt_len; ++ int txt_len, first, skip; + char *p; ++ const char *str; + + if ((size_t) trunc_len > sizeof (x) - 1) { + trunc_len = sizeof (x) - 1; + } +- txt_len = strlen (txt); +- if (txt_len <= trunc_len) { +- strcpy (x, txt); +- } else { +- int y = (trunc_len / 2) + (trunc_len % 2); +- strncpy (x, txt, y); +- strncpy (x + y, txt + txt_len - (trunc_len / 2), trunc_len / 2); +- x[y] = '~'; ++ txt_len = mbstrlen (txt); ++ first = 0; ++ skip = 0; ++ if (txt_len > trunc_len) { ++ first = trunc_len / 2; ++ skip = txt_len - trunc_len + 1; + } +- x[trunc_len] = 0; +- for (p = x; *p; p++) +- if (!is_printable (*p)) +- *p = '?'; ++ ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) { ++ mbstate_t s; ++ int mbmax; ++ ++ str = txt; ++ memset (&s, 0, sizeof (s)); ++ mbmax = MB_CUR_MAX; ++ p = x; ++ while (p < x + sizeof (x) - 1 && trunc_len) { ++ wchar_t wc; ++ int len; ++ ++ len = mbrtowc (&wc, str, mbmax, &s); ++ if (!len) ++ break; ++ if (len < 0) { ++ memset (&s, 0, sizeof (s)); ++ *p = '?'; ++ len = 1; ++ str++; ++ } else if (!is_printable (wc)) { ++ *p = '?'; ++ str += len; ++ len = 1; ++ } else if (p >= x + sizeof (x) - len) ++ break; ++ else { ++ memcpy (p, str, len); ++ str += len; ++ } ++ if (first) { ++ --trunc_len; ++ --first; ++ p += len; ++ if (!first && p < x + sizeof (x) - 1 && trunc_len) { ++ *p++ = '~'; ++ --trunc_len; ++ } ++ } else if (skip) ++ --skip; ++ else { ++ --trunc_len; ++ p += len; ++ } ++ } ++ } else ++#endif ++ { ++ str = txt; ++ p = x; ++ while (p < x + sizeof (x) - 1) { ++ if (*str == '\0') ++ break; ++ else if (!is_printable (*str)) ++ *p++ = '?'; ++ else ++ *p++ = *str; ++ ++str; ++ if (first) { ++ --first; ++ if (!first) { ++ *p++ = '~'; ++ str += skip; ++ } ++ } ++ } ++ } ++ *p = '\0'; + return x; + } + +@@ -683,11 +909,66 @@ load_file (const char *filename) + } + + char * ++utf8_to_local(char *str) ++{ ++ iconv_t cd; ++ size_t buflen; ++ char *output; ++ int retry = 1; ++ ++ if (!str) ++ return 0; ++ ++ buflen = strlen(str); ++ ++ cd = iconv_open (nl_langinfo(CODESET), "UTF-8"); ++ if (cd == (iconv_t) -1) { ++ return g_strdup(str); ++ } ++ ++ output = g_malloc(buflen + 1); ++ ++ while (retry) ++ { ++ char *wrptr = output; ++ char *inptr = str; ++ size_t insize = buflen; ++ size_t avail = buflen; ++ size_t nconv; ++ ++ nconv = iconv (cd, &inptr, &insize, &wrptr, &avail); ++ if (nconv == (size_t) -1) ++ { ++ if (errno == E2BIG) ++ { ++ buflen *= 2; ++ g_free(output); ++ output = g_malloc(buflen + 1); ++ } ++ else ++ { ++ g_free(output); ++ return g_strdup(str); ++ } ++ } ++ else { ++ retry = 0; ++ *wrptr = 0; ++ } ++ } ++ ++ iconv_close (cd); ++ ++ return output; ++} ++ ++char * + load_mc_home_file (const char *filename, char **allocated_filename) + { + char *hintfile_base, *hintfile; + char *lang; + char *data; ++ char *conv_data; + + hintfile_base = mhl_str_dir_plus_file (mc_home, filename); + lang = guess_message_value (); +@@ -720,7 +1001,10 @@ load_mc_home_file (const char *filename, char **allocated_filename) + else + g_free (hintfile); + +- return data; ++ conv_data = utf8_to_local(data); ++ g_free(data); ++ ++ return conv_data; + } + + /* Check strftime() results. Some systems (i.e. Solaris) have different +@@ -736,10 +1020,12 @@ i18n_checktimelength (void) + // huh, localtime() doesnt seem to work ... falling back to "(invalid)" + length = strlen(INVALID_TIME_TEXT); + } else { +- char buf [MAX_I18NTIMELENGTH + 1]; ++ char buf [4* MAX_I18NTIMELENGTH + 1]; + size_t a, b; +- a = strftime (buf, sizeof(buf)-1, _("%b %e %H:%M"), lt); +- b = strftime (buf, sizeof(buf)-1, _("%b %e %Y"), lt); ++ strftime (buf, sizeof(buf)-1, _("%b %e %H:%M"), lt); ++ a = mbstrlen(buf); ++ strftime (buf, sizeof(buf)-1, _("%b %e %Y"), lt); ++ b = mbstrlen(buf); + length = max (a, b); + } + +@@ -753,15 +1039,12 @@ i18n_checktimelength (void) + const char * + file_date (time_t when) + { +- static char timebuf [MAX_I18NTIMELENGTH + 1]; ++ static char timebuf [4 * MAX_I18NTIMELENGTH + 1]; + time_t current_time = time ((time_t) 0); +- static size_t i18n_timelength = 0; + static const char *fmtyear, *fmttime; + const char *fmt; + +- if (i18n_timelength == 0){ +- i18n_timelength = i18n_checktimelength() + 1; +- ++ if ( fmtyear == NULL ) { + /* strftime() format string for old dates */ + fmtyear = _("%b %e %Y"); + /* strftime() format string for recent dates */ +@@ -781,7 +1064,7 @@ file_date (time_t when) + else + fmt = fmttime; + +- FMT_LOCALTIME(timebuf, i18n_timelength, fmt, when); ++ FMT_LOCALTIME(timebuf, sizeof(timebuf), fmt, when); + + return timebuf; + } +@@ -912,10 +1195,27 @@ strip_ctrl_codes (char *s) + r++; + continue; + } +- ++#ifndef UTF8 + if (is_printable(*r)) + *w++ = *r; + ++r; ++#else /* UTF8 */ ++ { ++ mbstate_t mbs; ++ int len; ++ memset (&mbs, 0, sizeof (mbs)); ++ len = mbrlen(r, MB_CUR_MAX, &mbs); ++ ++ if (len > 0 && (unsigned char)*r >= ' ') ++ while (len--) ++ *w++ = *r++; ++ else { ++ if (len == -1) ++ *w++ = '?'; ++ r++; ++ } ++ } ++#endif /* UTF8 */ + } + *w = 0; + return s; +diff --git a/src/util.h b/src/util.h +index 0cf2099..82edcde 100644 +--- a/src/util.h ++++ b/src/util.h +@@ -102,6 +102,13 @@ void init_uid_gid_cache (void); + char *get_group (int); + char *get_owner (int); + ++void fix_utf8(char *str); ++size_t mbstrlen (const char *); ++wchar_t *mbstr_to_wchar (const char *); ++char *wchar_to_mbstr (const wchar_t *); ++char *utf8_to_local(char *str); ++ ++ + #define MAX_I18NTIMELENGTH 14 + #define MIN_I18NTIMELENGTH 10 + #define STD_I18NTIMELENGTH 12 +diff --git a/src/view.c b/src/view.c +index 8465301..8bc1792 100644 +--- a/src/view.c ++++ b/src/view.c +@@ -44,6 +44,10 @@ + #include + #include + ++#ifdef UTF8 ++#include ++#endif /* UTF8 */ ++ + #include "global.h" + #include "tty.h" + #include "cmd.h" /* For view_other_cmd */ +@@ -1643,7 +1647,7 @@ view_display_status (WView *view) + hline (' ', width); + + file_label = _("File: %s"); +- file_label_width = strlen (file_label) - 2; ++ file_label_width = mbstrlen (file_label) - 2; + file_name = view->filename ? view->filename + : view->command ? view->command + : ""; +@@ -1911,6 +1915,12 @@ view_display_text (WView * view) + offset_type from; + int c; + struct hexedit_change_node *curr = view->change_list; ++#ifdef UTF8 ++ mbstate_t mbs; ++ char mbbuf[MB_LEN_MAX]; ++ int mblen; ++ wchar_t wc; ++#endif /* UTF8 */ + + view_display_clean (view); + view_display_ruler (view); +@@ -1923,8 +1933,37 @@ view_display_text (WView * view) + + tty_setcolor (NORMAL_COLOR); + for (row = 0, col = 0; row < height && (c = get_byte (view, from)) != -1; from++) { +- ++#ifndef UTF8 + if (view->text_nroff_mode && c == '\b') { ++#else /* UTF8 */ ++ mblen = 1; ++ mbbuf[0] = convert_to_display_c (c); ++ ++ while (mblen < MB_LEN_MAX) { ++ int res; ++ memset (&mbs, 0, sizeof (mbs)); ++ res = mbrtowc (&wc, mbbuf, mblen, &mbs); ++ if (res <= 0 && res != -2) { ++ wc = '.'; ++ mblen = 1; ++ break; ++ } ++ if (res == mblen) ++ break; ++ ++ mbbuf[mblen] = convert_to_display_c (get_byte (view, from + mblen)); ++ mblen++; ++ } ++ ++ if (mblen == MB_LEN_MAX) { ++ wc = '.'; ++ mblen = 1; ++ } ++ ++ from += mblen - 1; ++ ++ if (view->text_nroff_mode && wc == '\b') { ++#endif /* UTF8 */ + int c_prev; + int c_next; + +@@ -1989,10 +2028,17 @@ view_display_text (WView * view) + if (col >= view->dpy_text_column + && col - view->dpy_text_column < width) { + widget_move (view, top + row, left + (col - view->dpy_text_column)); ++#ifndef UTF8 + c = convert_to_display_c (c); + if (!is_printable (c)) + c = '.'; + tty_print_char (c); ++#else ++ wc = convert_to_display_c (wc); ++ if (!iswprint (wc)) ++ wc = '.'; ++ tty_print_char (wc); ++#endif + } + col++; + tty_setcolor (NORMAL_COLOR); +@@ -3187,7 +3233,7 @@ view_handle_key (WView *view, int c) + + #ifdef HAVE_CHARSET + case XCTRL ('t'): +- do_select_codepage (); ++ do_select_codepage (_(" Choose codepage ")); + view->dirty++; + view_update (view); + return MSG_HANDLED; +diff --git a/src/widget.c b/src/widget.c +index f85cc2a..635441d 100644 +--- a/src/widget.c ++++ b/src/widget.c +@@ -38,6 +38,9 @@ + + #include "global.h" + #include "tty.h" ++#ifdef UTF8 ++#include ++#endif /* UTF8 */ + #include "color.h" + #include "mouse.h" + #include "dialog.h" +@@ -183,6 +186,11 @@ button_callback (Widget *w, widget_msg_t msg, int parm) + if (b->hotpos >= 0) { + widget_selectcolor (w, b->selected, TRUE); + widget_move (w, 0, b->hotpos + off); ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) ++ SLsmg_write_nwchars (&b->hotwc, 1); ++ else ++#endif + addch ((unsigned char) b->text[b->hotpos]); + } + return MSG_HANDLED; +@@ -216,7 +224,7 @@ button_event (Gpm_Event *event, void *data) + static int + button_len (const char *text, unsigned int flags) + { +- int ret = strlen (text); ++ int ret = mbstrlen (text); + switch (flags){ + case DEFPUSH_BUTTON: + ret += 6; +@@ -239,14 +247,36 @@ button_len (const char *text, unsigned int flags) + * the button text is g_malloc()ed, we can safely change and shorten it. + */ + static void +-button_scan_hotkey (WButton *b) ++scan_hotkey (char *text, int *hotposp, int *hotkeyp, wchar_t *hotwcp) + { +- char *cp = strchr (b->text, '&'); ++ char *cp = strchr (text, '&'); + + if (cp != NULL && cp[1] != '\0') { +- g_strlcpy (cp, cp + 1, strlen (cp)); +- b->hotkey = tolower ((unsigned char) *cp); +- b->hotpos = cp - b->text; ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) { ++ mbstate_t s; ++ int len; ++ ++ *cp = '\0'; ++ memset (&s, 0, sizeof (s)); ++ len = mbrtowc (hotwcp, cp + 1, MB_CUR_MAX, &s); ++ if (len > 0) { ++ *hotposp = mbstrlen (text); ++ if (*hotposp < 0) { ++ *hotposp = -1; ++ } else { ++ /* FIXME */ ++ *hotkeyp = tolower (*hotwcp); ++ } ++ } ++ } else ++#endif ++ { ++ *hotkeyp = tolower (cp[1]); ++ *hotposp = cp - text; ++ } ++ ++ memmove (cp, cp + 1, strlen (cp + 1) + 1); + } + } + +@@ -267,8 +297,9 @@ button_new (int y, int x, int action, int flags, const char *text, + widget_want_hotkey (b->widget, 1); + b->hotkey = 0; + b->hotpos = -1; ++ b->hotwc = L'\0'; + +- button_scan_hotkey(b); ++ scan_hotkey(b->text, &b->hotpos, &b->hotkey, &b->hotwc); + return b; + } + +@@ -281,14 +312,13 @@ button_get_text (WButton *b) + void + button_set_text (WButton *b, const char *text) + { +- g_free (b->text); ++ g_free (b->text); + b->text = g_strdup (text); + b->widget.cols = button_len (text, b->flags); +- button_scan_hotkey(b); ++ scan_hotkey(b->text, &b->hotpos, &b->hotkey, &b->hotwc); + dlg_redraw (b->widget.parent); + } + +- + /* Radio button widget */ + static int radio_event (Gpm_Event *event, void *); + +@@ -363,14 +393,35 @@ radio_callback (Widget *w, widget_msg_t msg, int parm) + widget_move (&r->widget, i, 0); + + tty_printf ("(%c) ", (r->sel == i) ? '*' : ' '); +- for (cp = r->texts[i]; *cp; cp++) { +- if (*cp == '&') { +- widget_selectcolor (w, focused, TRUE); ++ cp = strchr (r->texts[i], '&'); ++ if (cp != NULL) { ++#ifdef UTF8 ++ mbstate_t s; ++ wchar_t wc; ++ int len; ++#endif ++ tty_printf ("%.*s", (int) ((char *) cp - r->texts[i]), ++ r->texts[i]); ++ widget_selectcolor (w, focused, TRUE); ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) { ++ memset (&s, 0, sizeof (s)); ++ len = mbrtowc (&wc, cp + 1, MB_CUR_MAX, &s); ++ ++cp; ++ if (len > 0) { ++ tty_printf ("%.*s", len, cp); ++ cp += len; ++ } ++ } else ++#endif ++ { + addch (*++cp); +- widget_selectcolor (w, focused, FALSE); +- } else +- addch (*cp); +- } ++ ++cp; ++ } ++ widget_selectcolor (w, focused, FALSE); ++ } else ++ cp = r->texts[i]; ++ addstr ((char *) cp); + } + return MSG_HANDLED; + +@@ -409,7 +460,7 @@ radio_new (int y, int x, int count, const char **texts) + /* Compute the longest string */ + max = 0; + for (i = 0; i < count; i++){ +- m = strlen (texts [i]); ++ m = mbstrlen (texts [i]); + if (m > max) + max = m; + } +@@ -469,6 +520,11 @@ check_callback (Widget *w, widget_msg_t msg, int parm) + if (c->hotpos >= 0) { + widget_selectcolor (w, msg == WIDGET_FOCUS, TRUE); + widget_move (&c->widget, 0, +c->hotpos + 4); ++#ifdef UTF8 ++ if (SLsmg_Is_Unicode) ++ SLsmg_write_nwchars (&c->hotwc, 1); ++ else ++#endif + addch ((unsigned char) c->text[c->hotpos]); + } + return MSG_HANDLED; +@@ -506,35 +562,20 @@ WCheck * + check_new (int y, int x, int state, const char *text) + { + WCheck *c = g_new (WCheck, 1); +- const char *s; +- char *t; +- +- init_widget (&c->widget, y, x, 1, strlen (text), ++ ++ init_widget (&c->widget, y, x, 1, mbstrlen (text), + check_callback, check_event); + c->state = state ? C_BOOL : 0; + c->text = g_strdup (text); + c->hotkey = 0; + c->hotpos = -1; ++ c->hotwc = L'\0'; + widget_want_hotkey (c->widget, 1); + +- /* Scan for the hotkey */ +- for (s = text, t = c->text; *s; s++, t++){ +- if (*s != '&'){ +- *t = *s; +- continue; +- } +- s++; +- if (*s){ +- c->hotkey = tolower ((unsigned char) *s); +- c->hotpos = t - c->text; +- } +- *t = *s; +- } +- *t = 0; ++ scan_hotkey (c->text, &c->hotpos, &c->hotkey, &c->hotwc); + return c; + } + +- + /* Label widget */ + + static cb_ret_t +@@ -573,7 +614,7 @@ label_callback (Widget *w, widget_msg_t msg, int parm) + } + widget_move (&l->widget, y, 0); + tty_printf ("%s", p); +- xlen = l->widget.cols - strlen (p); ++ xlen = l->widget.cols - mbstrlen (p); + if (xlen > 0) + tty_printf ("%*s", xlen, " "); + if (!q) +@@ -607,7 +648,7 @@ label_set_text (WLabel *label, const char *text) + if (text){ + label->text = g_strdup (text); + if (label->auto_adjust_cols) { +- newcols = strlen (text); ++ newcols = mbstrlen (text); + if (newcols > label->widget.cols) + label->widget.cols = newcols; + } +@@ -631,7 +672,7 @@ label_new (int y, int x, const char *text) + if (!text || strchr(text, '\n')) + width = 1; + else +- width = strlen (text); ++ width = mbstrlen (text); + + l = g_new (WLabel, 1); + init_widget (&l->widget, y, x, 1, width, label_callback, NULL); +@@ -779,13 +820,69 @@ static void draw_history_button (WInput * in) + /* Pointer to killed data */ + static char *kill_buffer = 0; + ++#ifdef UTF8 ++static int ++charpos(WInput *in, int idx) ++{ ++ int i, pos, l, len; ++ mbstate_t mbs; ++ memset (&mbs, 0, sizeof (mbs)); ++ i = 0; ++ pos = 0; ++ len = strlen(in->buffer); ++ ++ while (in->buffer[pos]) { ++ if (i == idx) ++ return pos; ++ l = mbrlen(in->buffer + pos, len - pos, &mbs); ++ if (l <= 0) ++ return pos; ++ pos+=l; ++ i++; ++ }; ++ return pos; ++} ++ ++static int ++charcolumn(WInput *in, int idx) ++{ ++ int i, pos, l, width, len; ++ mbstate_t mbs; ++ memset (&mbs, 0, sizeof (mbs)); ++ i = 0; ++ pos = 0; width = 0; ++ len = strlen(in->buffer); ++ ++ while (in->buffer[pos]) { ++ wchar_t wc; ++ if (i == idx) ++ return width; ++ l = mbrtowc(&wc, in->buffer + pos, len - pos, &mbs); ++ if (l <= 0) ++ return width; ++ pos += l; width += wcwidth(wc); ++ i++; ++ }; ++ return width; ++} ++#else ++#define charpos(in, idx) (idx) ++#define charcolumn(in, idx) (idx) ++#endif /* UTF8 */ ++ + void + update_input (WInput *in, int clear_first) + { + int has_history = 0; + int i, j; +- unsigned char c; +- int buf_len = strlen (in->buffer); ++ int buf_len = mbstrlen (in->buffer); ++#ifndef UTF8 ++ unsigned char c; ++#else /* UTF8 */ ++ wchar_t c; ++ mbstate_t mbs; ++ memset (&mbs, 0, sizeof (mbs)); ++#endif /* UTF8 */ + + if (should_show_history_button (in)) + has_history = HISTORY_BUTTON_WIDTH; +@@ -795,7 +892,7 @@ update_input (WInput *in, int clear_first) + + /* Make the point visible */ + if ((in->point < in->first_shown) || +- (in->point >= in->first_shown+in->field_len - has_history)){ ++ (charcolumn(in, in->point) >= charcolumn(in, in->first_shown) + in->field_len - has_history)){ + in->first_shown = in->point - (in->field_len / 3); + if (in->first_shown < 0) + in->first_shown = 0; +@@ -815,14 +912,29 @@ update_input (WInput *in, int clear_first) + addch (' '); + widget_move (&in->widget, 0, 0); + ++#ifndef UTF8 + for (i = 0, j = in->first_shown; i < in->field_len - has_history && in->buffer [j]; i++){ + c = in->buffer [j++]; + c = is_printable (c) ? c : '.'; ++#else /* UTF8 */ ++ for (i = 0, j = in->first_shown; (i < in->field_len - has_history) && (j < buf_len); i++,j++){ ++ char * chp = in->buffer + charpos(in,j); ++ size_t res = mbrtowc(&c, chp, strlen(chp), &mbs); ++ c = (res && iswprint (c)) ? 0 : '.'; ++#endif /* UTF8 */ + if (in->is_password) + c = '*'; ++#ifndef UTF8 + addch (c); ++#else /* UTF8 */ ++ if (c) { ++ addch (c); ++ } ++ else ++ SLsmg_write_nchars (chp, res); ++#endif /* UTF8 */ + } +- widget_move (&in->widget, 0, in->point - in->first_shown); ++ widget_move (&in->widget, 0, charcolumn(in, in->point) - charcolumn(in, in->first_shown)); + + if (clear_first) + in->first = 0; +@@ -975,7 +1087,7 @@ char * + show_hist (GList *history, int widget_x, int widget_y) + { + GList *hi, *z; +- size_t maxlen = strlen (i18n_htitle ()), i, count = 0; ++ size_t maxlen = mbstrlen (i18n_htitle ()), i, count = 0; + int x, y, w, h; + char *q, *r = 0; + Dlg_head *query_dlg; +@@ -988,7 +1100,7 @@ show_hist (GList *history, int widget_x, int widget_y) + z = g_list_first (history); + hi = z; + while (hi) { +- if ((i = strlen ((char *) hi->data)) > maxlen) ++ if ((i = mbstrlen ((char *) hi->data)) > maxlen) + maxlen = i; + count++; + hi = g_list_next (hi); +@@ -1158,35 +1270,83 @@ new_input (WInput *in) + in->need_push = 1; + in->buffer [0] = 0; + in->point = 0; ++ in->charpoint = 0; + in->mark = 0; + free_completions (in); + update_input (in, 0); + } + ++static void ++move_buffer_backward (WInput *in, int point) ++{ ++ int i, pos, len; ++ int str_len = mbstrlen (in->buffer); ++ if (point >= str_len) return; ++ ++ pos = charpos(in,point); ++ len = charpos(in,point + 1) - pos; ++ ++ for (i = pos; in->buffer [i + len - 1]; i++) ++ in->buffer [i] = in->buffer [i + len]; ++} ++ + static cb_ret_t + insert_char (WInput *in, int c_code) + { + size_t i; ++#ifdef UTF8 ++ mbstate_t mbs; ++ int res; ++ ++ memset (&mbs, 0, sizeof (mbs)); ++#else ++ in->charpoint = 0; ++#endif /* UTF8 */ + + if (c_code == -1) + return MSG_NOT_HANDLED; + ++#ifdef UTF8 ++ if (in->charpoint >= MB_CUR_MAX) return 1; ++ ++ in->charbuf[in->charpoint++] = c_code; ++ ++ res = mbrlen((char *)in->charbuf, in->charpoint, &mbs); ++ if (res < 0) { ++ if (res != -2) in->charpoint = 0; /* broken multibyte char, skip */ ++ return 1; ++ } ++ ++#endif /* UTF8 */ + in->need_push = 1; +- if (strlen (in->buffer)+1 == (size_t) in->current_max_len){ ++ if (strlen (in->buffer) + 1 + in->charpoint >= (size_t) in->current_max_len){ + /* Expand the buffer */ +- char *narea = g_realloc (in->buffer, in->current_max_len + in->field_len); ++ char *narea = g_realloc (in->buffer, in->current_max_len + in->field_len + in->charpoint); + if (narea){ + in->buffer = narea; +- in->current_max_len += in->field_len; ++ in->current_max_len += in->field_len + in->charpoint; + } + } ++#ifndef UTF8 + if (strlen (in->buffer)+1 < (size_t) in->current_max_len){ + size_t l = strlen (&in->buffer [in->point]); + for (i = l+1; i > 0; i--) + in->buffer [in->point+i] = in->buffer [in->point+i-1]; + in->buffer [in->point] = c_code; ++#else /* UTF8 */ ++ if (strlen (in->buffer) + in->charpoint < in->current_max_len){ ++ size_t ins_point = charpos(in,in->point); /* bytes from begin */ ++ /* move chars */ ++ size_t rest_bytes = strlen (in->buffer + ins_point); ++ ++ for (i = rest_bytes + 1; i > 0; i--) ++ in->buffer [ins_point + i + in->charpoint - 1] = in->buffer [ins_point + i - 1]; ++ ++ memcpy(in->buffer + ins_point, in->charbuf, in->charpoint); ++#endif /* UTF8 */ + in->point++; + } ++ in->charpoint = 0; + return MSG_HANDLED; + } + +@@ -1194,12 +1354,14 @@ static void + beginning_of_line (WInput *in) + { + in->point = 0; ++ in->charpoint = 0; + } + + static void + end_of_line (WInput *in) + { +- in->point = strlen (in->buffer); ++ in->point = mbstrlen (in->buffer); ++ in->charpoint = 0; + } + + static void +@@ -1207,18 +1369,21 @@ backward_char (WInput *in) + { + if (in->point) + in->point--; ++ in->charpoint = 0; + } + + static void + forward_char (WInput *in) + { +- if (in->buffer [in->point]) ++ if (in->buffer [charpos(in,in->point)]) + in->point++; ++ in->charpoint = 0; + } + + static void + forward_word (WInput * in) + { ++#ifndef UTF8 + char *p = in->buffer + in->point; + + while (*p +@@ -1228,11 +1393,39 @@ forward_word (WInput * in) + while (*p && isalnum ((unsigned char) *p)) + p++; + in->point = p - in->buffer; ++#else /* UTF8 */ ++ mbstate_t mbs; ++ int len = mbstrlen (in->buffer); ++ memset (&mbs, 0, sizeof (mbs)); ++ ++ while (in->point < len) { ++ wchar_t c; ++ char *p = in->buffer + charpos(in,in->point); ++ size_t res = mbrtowc(&c, p, strlen(p), &mbs); ++ if (res <= 0 || !(iswspace (c) || iswpunct (c))) ++ break; ++ in->point++; ++ } ++ ++ memset (&mbs, 0, sizeof (mbs)); ++ ++ while (in->point < len) { ++ wchar_t c; ++ char *p = in->buffer + charpos(in,in->point); ++ size_t res = mbrtowc(&c, p, strlen(p), &mbs); ++ if (res <= 0 || !iswalnum (c)) ++ break; ++ in->point++; ++ } ++ ++ in->charpoint = 0; ++#endif /* UTF8 */ + } + + static void + backward_word (WInput *in) + { ++#ifndef UTF8 + char *p = in->buffer + in->point; + + while (p - 1 > in->buffer - 1 && (isspace ((unsigned char) *(p - 1)) +@@ -1242,6 +1435,32 @@ backward_word (WInput *in) + while (p - 1 > in->buffer - 1 && isalnum ((unsigned char) *(p - 1))) + p--; + in->point = p - in->buffer; ++#else /* UTF8 */ ++ mbstate_t mbs; ++ ++ memset (&mbs, 0, sizeof (mbs)); ++ while (in->point > 0) { ++ wchar_t c; ++ char *p = in->buffer + charpos(in,in->point); ++ size_t res = mbrtowc(&c, p, strlen(p), &mbs); ++ if (*p && (res <= 0 || !(iswspace (c) || iswpunct (c)))) ++ break; ++ in->point--; ++ } ++ ++ memset (&mbs, 0, sizeof (mbs)); ++ ++ while (in->point > 0) { ++ wchar_t c; ++ char *p = in->buffer + charpos(in,in->point); ++ size_t res = mbrtowc(&c, p, strlen(p), &mbs); ++ if (*p && (res <= 0 || !iswalnum (c))) ++ break; ++ in->point--; ++ } ++ ++ in->charpoint = 0; ++#endif /* UTF8 */ + } + + static void +@@ -1270,12 +1489,12 @@ key_ctrl_right (WInput *in) + static void + backward_delete (WInput *in) + { +- int i; + + if (!in->point) + return; +- for (i = in->point; in->buffer [i-1]; i++) +- in->buffer [i-1] = in->buffer [i]; ++ ++ move_buffer_backward(in, in->point - 1); ++ in->charpoint = 0; + in->need_push = 1; + in->point--; + } +@@ -1283,10 +1502,8 @@ backward_delete (WInput *in) + static void + delete_char (WInput *in) + { +- int i; +- +- for (i = in->point; in->buffer [i]; i++) +- in->buffer [i] = in->buffer [i+1]; ++ move_buffer_backward(in, in->point); ++ in->charpoint = 0; + in->need_push = 1; + } + +@@ -1301,6 +1518,9 @@ copy_region (WInput *in, int x_first, int x_last) + + g_free (kill_buffer); + ++ first=charpos(in,first); ++ last=charpos(in,last); ++ + kill_buffer = g_strndup(in->buffer+first,last-first); + } + +@@ -1309,11 +1529,13 @@ delete_region (WInput *in, int x_first, int x_last) + { + int first = min (x_first, x_last); + int last = max (x_first, x_last); +- size_t len = strlen (&in->buffer [last]) + 1; ++ size_t len; + + in->point = first; + in->mark = first; +- memmove (&in->buffer [first], &in->buffer [last], len); ++ len = strlen (&in->buffer [charpos(in,last)]) + 1; ++ memmove (&in->buffer [charpos(in,first)], &in->buffer [charpos(in,last)], len); ++ in->charpoint = 0; + in->need_push = 1; + } + +@@ -1330,6 +1552,8 @@ kill_word (WInput *in) + copy_region (in, old_point, new_point); + delete_region (in, old_point, new_point); + in->need_push = 1; ++ in->charpoint = 0; ++ in->charpoint = 0; + } + + static void +@@ -1373,16 +1597,20 @@ yank (WInput *in) + + if (!kill_buffer) + return; ++ in->charpoint = 0; + for (p = kill_buffer; *p; p++) + insert_char (in, *p); ++ in->charpoint = 0; + } + + static void + kill_line (WInput *in) + { ++ int chp = charpos(in,in->point); + g_free (kill_buffer); +- kill_buffer = g_strdup (&in->buffer [in->point]); +- in->buffer [in->point] = 0; ++ kill_buffer = g_strdup (&in->buffer [chp]); ++ in->buffer [chp] = 0; ++ in->charpoint = 0; + } + + void +@@ -1392,9 +1620,10 @@ assign_text (WInput *in, const char *text) + g_free (in->buffer); + in->buffer = g_strdup (text); /* was in->buffer->text */ + in->current_max_len = strlen (in->buffer) + 1; +- in->point = strlen (in->buffer); ++ in->point = mbstrlen (in->buffer); + in->mark = 0; + in->need_push = 1; ++ in->charpoint = 0; + } + + static void +@@ -1521,6 +1750,7 @@ port_region_marked_for_delete (WInput *in) + *in->buffer = 0; + in->point = 0; + in->first = 0; ++ in->charpoint = 0; + } + + cb_ret_t +@@ -1549,7 +1779,11 @@ handle_char (WInput *in, int c_code) + } + } + if (!input_map [i].fn){ ++#ifndef UTF8 + if (c_code > 255 || !is_printable (c_code)) ++#else /* UTF8 */ ++ if (c_code > 255) ++#endif /* UTF8 */ + return MSG_NOT_HANDLED; + if (in->first){ + port_region_marked_for_delete (in); +@@ -1582,6 +1816,9 @@ input_set_point (WInput *in, int pos) + if (pos != in->point) + free_completions (in); + in->point = pos; ++#ifdef UTF8 ++ in->charpoint = 0; ++#endif /* UTF8 */ + update_input (in, 1); + } + +@@ -1622,7 +1859,7 @@ input_callback (Widget *w, widget_msg_t msg, int parm) + return MSG_HANDLED; + + case WIDGET_CURSOR: +- widget_move (&in->widget, 0, in->point - in->first_shown); ++ widget_move (&in->widget, 0, charcolumn(in, in->point) - charcolumn(in, in->first_shown)); + return MSG_HANDLED; + + case WIDGET_DESTROY: +@@ -1646,7 +1883,7 @@ input_event (Gpm_Event * event, void *data) + && should_show_history_button (in)) { + do_show_hist (in); + } else { +- in->point = strlen (in->buffer); ++ in->point = mbstrlen (in->buffer); + if (event->x - in->first_shown - 1 < in->point) + in->point = event->x - in->first_shown - 1; + if (in->point < 0) +@@ -1701,56 +1938,91 @@ input_new (int y, int x, int color, int len, const char *def_text, + in->is_password = 0; + + strcpy (in->buffer, def_text); +- in->point = strlen (in->buffer); ++ in->point = mbstrlen (in->buffer); ++ in->charpoint = 0; + return in; + } + +- +-/* Listbox widget */ ++/* Vertical scrollbar widget */ + +-/* Should draw the scrollbar, but currently draws only +- * indications that there is more information +- */ +-static int listbox_cdiff (WLEntry *s, WLEntry *e); +- +-static void +-listbox_drawscroll (WListbox *l) ++void ++vscrollbar (Widget widget, int height, int width, int tpad, int bpad, ++ int selected, int count, gboolean color) + { + int line; +- int i, top; +- int max_line = l->height-1; +- ++ int i; ++ + /* Are we at the top? */ +- widget_move (&l->widget, 0, l->width); +- if (l->list == l->top) +- one_vline (); ++ widget_move (&widget, tpad, width); ++#ifndef UTF8 ++ if (!selected) ++ one_vline (); ++ else ++ addch ('^'); ++#else ++ if (color) attrset (MARKED_COLOR); ++ if (is_utf8) ++ SLsmg_write_string("â–´"); + else +- addch ('^'); ++ addch ('^'); ++ if (color) attrset (NORMAL_COLOR); ++#endif + + /* Are we at the bottom? */ +- widget_move (&l->widget, max_line, l->width); +- top = listbox_cdiff (l->list, l->top); +- if ((top + l->height == l->count) || l->height >= l->count) +- one_vline (); ++ widget_move (&widget, height-1-bpad, width); ++#ifndef UTF8 ++ if (selected == count-1) ++ one_vline (); ++ else ++ addch ('v'); ++#else ++ if (color) attrset (MARKED_COLOR); ++ if (is_utf8) ++ SLsmg_write_string("â–¾"); + else +- addch ('v'); ++ addch('v'); ++ if (color) attrset (NORMAL_COLOR); ++#endif + + /* Now draw the nice relative pointer */ +- if (l->count) +- line = 1+ ((l->pos * (l->height-2)) / l->count); ++ if (count > 1) ++ line = tpad + 1 + ((selected * (height-3-tpad-bpad)) / (count-1)); + else +- line = 0; +- +- for (i = 1; i < max_line; i++){ +- widget_move (&l->widget, i, l->width); +- if (i != line) +- one_vline (); +- else +- addch ('*'); ++ line = 0; ++ ++ for (i = tpad + 1; i < height-1-bpad; i++){ ++ widget_move (&widget, i, width); ++ if (i != line) ++#ifndef UTF8 ++ one_vline (); ++ else ++ addch ('*'); ++#else ++ if (is_utf8) ++ SLsmg_write_string("â–’"); ++ else ++ one_vline(); ++ else { ++ if (color) attrset (MARKED_COLOR); ++ if (is_utf8) ++ SLsmg_write_string("â—ˆ"); ++ else ++ addch('*'); ++ if (color) attrset (NORMAL_COLOR); ++ } ++#endif + } + } +- +-static void ++ ++ ++/* Listbox widget */ ++ ++/* Should draw the scrollbar, but currently draws only ++ * indications that there is more information ++ */ ++static int listbox_cdiff (WLEntry *s, WLEntry *e); ++ ++void + listbox_draw (WListbox *l, int focused) + { + WLEntry *e; +@@ -1791,7 +2063,7 @@ listbox_draw (WListbox *l, int focused) + if (!l->scrollbar) + return; + attrset (normalc); +- listbox_drawscroll (l); ++ vscrollbar (l->widget, l->height, l->width, 0, 0, l->pos, l->count, FALSE); + } + + /* Returns the number of items between s and e, +diff --git a/src/widget.h b/src/widget.h +index 8c6f781..d1d91f2 100644 +--- a/src/widget.h ++++ b/src/widget.h +@@ -39,6 +39,7 @@ typedef struct WButton { + char *text; /* text of button */ + int hotkey; /* hot KEY */ + int hotpos; /* offset hot KEY char in text */ ++ wchar_t hotwc; + bcback callback; /* Callback function */ + } WButton; + +@@ -59,6 +60,7 @@ typedef struct WCheck { + char *text; /* text of check button */ + int hotkey; /* hot KEY */ + int hotpos; /* offset hot KEY char in text */ ++ wchar_t hotwc; + } WCheck; + + typedef struct WGauge { +@@ -74,16 +76,20 @@ char *show_hist (GList *history, int widget_y, int widget_x); + + typedef struct { + Widget widget; +- int point; /* cursor position in the input line */ +- int mark; /* The mark position */ +- int first_shown; /* Index of the first shown character */ +- int current_max_len; /* Maximum length of input line */ +- int field_len; /* Length of the editing field */ ++ int point; /* cursor position in the input line (mb chars) */ ++ int mark; /* The mark position (mb chars) */ ++ int first_shown; /* Index of the first shown character (mb chars) */ ++ int current_max_len; /* Maximum length of input line (bytes) */ ++ int field_len; /* Length of the editing field (mb chars) */ + int color; /* color used */ + int first; /* Is first keystroke? */ + int disable_update; /* Do we want to skip updates? */ + int is_password; /* Is this a password input line? */ + char *buffer; /* pointer to editing buffer */ ++#ifdef UTF8 ++ char charbuf[MB_LEN_MAX]; ++#endif /* UTF8 */ ++ int charpoint; + GList *history; /* The history */ + int need_push; /* need to push the current Input on hist? */ + char **completions; /* Possible completions array */ +@@ -181,6 +187,10 @@ void button_set_text (WButton *b, const char *text); + /* Listbox manager */ + WLEntry *listbox_get_data (WListbox *l, int pos); + ++/* Vertical scrollbar */ ++void vscrollbar (Widget widget, int height, int width, int tpad, int bpad, ++ int selected, int count, gboolean color); ++ + /* search text int listbox entries */ + WLEntry *listbox_search_text (WListbox *l, const char *text); + void listbox_select_entry (WListbox *l, WLEntry *dest); +diff --git a/src/wtools.c b/src/wtools.c +index ba317e9..a6eaffa 100644 +--- a/src/wtools.c ++++ b/src/wtools.c +@@ -49,11 +49,11 @@ create_listbox_window (int cols, int lines, const char *title, const char *help) + /* Adjust sizes */ + lines = (lines > LINES - 6) ? LINES - 6 : lines; + +- if (title && (cols < (len = strlen (title) + 2))) ++ if (title && (cols < (len = mbstrlen (title) + 2))) + cols = len; + + /* no &, but 4 spaces around button for brackets and such */ +- if (cols < (len = strlen (cancel_string) + 3)) ++ if (cols < (len = mbstrlen (cancel_string) + 3)) + cols = len; + + cols = cols > COLS - 6 ? COLS - 6 : cols; +@@ -124,7 +124,7 @@ query_dialog (const char *header, const char *text, int flags, int count, ...) + va_start (ap, count); + for (i = 0; i < count; i++) { + char *cp = va_arg (ap, char *); +- win_len += strlen (cp) + 6; ++ win_len += mbstrlen (cp) + 6; + if (strchr (cp, '&') != NULL) + win_len--; + } +@@ -133,7 +133,7 @@ query_dialog (const char *header, const char *text, int flags, int count, ...) + + /* count coordinates */ + msglen (text, &lines, &cols); +- cols = 6 + max (win_len, max ((int) strlen (header), cols)); ++ cols = 6 + max (win_len, max ((int) mbstrlen (header), cols)); + lines += 4 + (count > 0 ? 2 : 0); + xpos = COLS / 2 - cols / 2; + ypos = LINES / 3 - (lines - 3) / 2; +@@ -148,7 +148,7 @@ query_dialog (const char *header, const char *text, int flags, int count, ...) + va_start (ap, count); + for (i = 0; i < count; i++) { + cur_name = va_arg (ap, char *); +- xpos = strlen (cur_name) + 6; ++ xpos = mbstrlen (cur_name) + 6; + if (strchr (cur_name, '&') != NULL) + xpos--; + +@@ -467,7 +467,7 @@ fg_input_dialog_help (const char *header, const char *text, const char *help, + } + + msglen (text, &lines, &cols); +- len = max ((int) strlen (header), cols) + 4; ++ len = max ((int) mbstrlen (header), cols) + 4; + len = max (len, 64); + + /* The special value of def_text is used to identify password boxes +@@ -489,7 +489,7 @@ fg_input_dialog_help (const char *header, const char *text, const char *help, + quick_widgets[1].text = _(quick_widgets[1].text); + quick_widgets[0].relative_x = len / 2 + 4; + quick_widgets[1].relative_x = +- len / 2 - (strlen (quick_widgets[1].text) + 9); ++ len / 2 - (mbstrlen (quick_widgets[1].text) + 9); + quick_widgets[0].x_divisions = quick_widgets[1].x_divisions = len; + #endif /* ENABLE_NLS */ + +diff --git a/vfs/vfs.c b/vfs/vfs.c +index 39fdc73..1658eaa 100644 +--- a/vfs/vfs.c ++++ b/vfs/vfs.c +@@ -56,6 +56,11 @@ + #include "smbfs.h" + #include "local.h" + ++#include "../src/panel.h" ++#ifdef HAVE_CHARSET ++#include "../src/recode.h" ++#endif ++ + /* They keep track of the current directory */ + static struct vfs_class *current_vfs; + static char *current_dir; +@@ -688,8 +693,66 @@ mc_chdir (const char *path) + vfsid old_vfsid; + int result; + ++#ifdef HAVE_CHARSET ++ char* errmsg; ++#endif ++ WPanel* p=ret_panel; ++ + new_dir = vfs_canon (path); + new_vfs = vfs_get_class (new_dir); ++ old_vfsid = vfs_getid (current_vfs, current_dir); ++ old_vfs = current_vfs; ++ ++ if(p) { ++ ++ // Change from localfs to ftpfs ++ ret_panel=NULL; ++ if( (strcmp(old_vfs->name,"localfs")==0) && ++ (strcmp(new_vfs->name,"ftpfs")==0)){ ++ p->is_return=1; ++ strncpy(p->retdir,current_dir, MC_MAXPATHLEN); ++#ifdef HAVE_CHARSET ++ p->ret_codepage=p->src_codepage; ++ p->src_codepage=ftp_codepage; ++ errmsg=my_init_tt(display_codepage,p->src_codepage,p->tr_table); ++ if(errmsg) { ++ panel_reset_codepage(p); ++ message( 1, MSG_ERROR, "%s", errmsg ); ++ } ++ errmsg=my_init_tt(p->src_codepage,display_codepage,p->tr_table_input); ++ if(errmsg) { ++ panel_reset_codepage(p); ++ message( 1, MSG_ERROR, "%s", errmsg ); ++ } ++#endif ++ } ++ ++ // Change from ftpfs to localfs ++ if( (strcmp(old_vfs->name,"ftpfs")==0) && ++ (strcmp(new_vfs->name,"localfs")==0) && ++ p->is_return){ ++ p->is_return=0; ++ g_free(new_dir); ++ new_dir = vfs_canon (p->retdir); ++ new_vfs = vfs_get_class (new_dir); ++#ifdef HAVE_CHARSET ++ p->src_codepage=p->ret_codepage; ++ errmsg=my_init_tt(display_codepage,p->src_codepage,p->tr_table); ++ if(errmsg) { ++ panel_reset_codepage(p); ++ message( 1, MSG_ERROR, "%s", errmsg ); ++ } ++ errmsg=my_init_tt(p->src_codepage,display_codepage,p->tr_table_input); ++ if(errmsg) { ++ panel_reset_codepage(p); ++ message( 1, MSG_ERROR, "%s", errmsg ); ++ } ++#endif ++ } ++ } ++ ++ ++ + if (!new_vfs->chdir) { + g_free (new_dir); + return -1; +@@ -703,9 +766,6 @@ mc_chdir (const char *path) + return -1; + } + +- old_vfsid = vfs_getid (current_vfs, current_dir); +- old_vfs = current_vfs; +- + /* Actually change directory */ + g_free (current_dir); + current_dir = new_dir; diff --git a/mc-4.7.0.1-extensions.patch b/mc-4.7.0.1-extensions.patch new file mode 100644 index 0000000..b5961a9 --- /dev/null +++ b/mc-4.7.0.1-extensions.patch @@ -0,0 +1,146 @@ +diff -up mc-4.7.0-pre4/configure.ac.extensions mc-4.7.0-pre4/configure.ac +--- mc-4.7.0-pre4/configure.ac.extensions 2009-10-30 19:44:38.000000000 +0100 ++++ mc-4.7.0-pre4/configure.ac 2009-12-10 20:41:43.000000000 +0100 +@@ -69,7 +69,7 @@ AC_PROG_LN_S + AC_CHECK_TOOL(AR, ar, ar) + + dnl Only list browsers here that can be run in background (i.e. with `&') +-AC_CHECK_PROGS(X11_WWW, [gnome-moz-remote mozilla konqueror opera netscape]) ++AC_CHECK_PROGS(X11_WWW, [firefox gnome-moz-remote mozilla konqueror opera netscape]) + + dnl + dnl Ovverriding mmap support. This has to be before AC_FUNC_MMAP is used. +diff -up mc-4.7.0-pre4/misc/mc.ext.in.extensions mc-4.7.0-pre4/misc/mc.ext.in +--- mc-4.7.0-pre4/misc/mc.ext.in.extensions 2009-10-29 20:02:37.000000000 +0100 ++++ mc-4.7.0-pre4/misc/mc.ext.in 2009-12-10 20:46:47.000000000 +0100 +@@ -226,8 +226,8 @@ regex/\.rpm$ + + # deb + regex/\.u?deb$ +- Open=%cd %p#deb +- View=%view{ascii} dpkg-deb -I %f && echo && dpkg-deb -c %f ++ Open=%cd %p#uar ++ View=%view{ascii} file %f && nm %f + + # dpkg + shell/.debd +@@ -387,7 +387,7 @@ shell/.ico + Include=image + + include/image +- Open=if [ "$DISPLAY" = "" ]; then zgv %f; else (gqview %f &); fi ++ Open=if [ "$DISPLAY" = "" ]; then zgv %f; else (eog %f &); fi + View=%view{ascii} identify %f + #View=%view{ascii} asciiview %f + +@@ -395,7 +395,8 @@ include/image + ### Sound files ### + + regex/\.([wW][aA][vV]|[sS][nN][dD]|[vV][oO][cC]|[aA][uU]|[sS][mM][pP]|[aA][iI][fF][fF]|[sS][nN][dD])$ +- Open=if [ "$DISPLAY" = "" ]; then play %f; else (xmms %f >/dev/null 2>&1 &); fi ++ Include=audio ++# Open=if [ "$DISPLAY" = "" ]; then play %f; else (xmms %f >/dev/null 2>&1 &); fi + + regex/\.([mM][oO][dD]|[sS]3[mM]|[xX][mM]|[iI][tT]|[mM][tT][mM]|669|[sS][tT][mM]|[uU][lL][tT]|[fF][aA][rR])$ + Open=mikmod %f +@@ -405,15 +406,22 @@ regex/\.([wW][aA][wW]22)$ + Open=vplay -s 22 %f + + regex/\.([mM][pP]3)$ +- Open=if [ "$DISPLAY" = "" ]; then mpg123 %f; else (xmms %f >/dev/null 2>&1 &); fi +- View=%view{ascii} mpg123 -vtn1 %f 2>&1 | sed -n '/^Title/,/^Comment/p;/^MPEG/,/^Audio/p' ++ Include=audio ++# Open=if [ "$DISPLAY" = "" ]; then mpg123 %f; else (xmms %f >/dev/null 2>&1 &); fi ++# View=%view{ascii} mpg123 -vtn1 %f 2>&1 | sed -n '/^Title/,/^Comment/p;/^MPEG/,/^Audio/p' ++ ++regex/\.([mM][kK][aA])$ ++ Include=audio + + regex/\.([oO][gG][gG|aA|vV|xX])$ +- Open=if [ "$DISPLAY" = "" ]; then ogg123 %f; else (xmms %f >/dev/null 2>&1 &); fi ++ Include=audio ++# Open=ogg123 %f ++# Open=if [ "$DISPLAY" = "" ]; then ogg123 %f; else (xmms %f >/dev/null 2>&1 &); fi + View=%view{ascii} ogginfo %s + + regex/\.([sS][pP][xX]|[fF][lL][aA][cC])$ +- Open=if [ "$DISPLAY" = "" ]; then play %f; else (xmms %f >/dev/null 2>&1 &); fi ++ Include=audio ++# Open=if [ "$DISPLAY" = "" ]; then play %f; else (xmms %f >/dev/null 2>&1 &); fi + + regex/\.([mM][iI][dD][iI]?|[rR][mM][iI][dD]?)$ + Open=timidity %f +@@ -422,11 +430,15 @@ regex/\.([wW][mM][aA])$ + Open=mplayer -vo null %f + View=%view{ascii} mplayer -quiet -slave -frames 0 -vo null -ao null -identify %f 2>/dev/null | tail +13 || file %f + ++include/audio ++ Open=mplayer %f ++ View=%view{ascii} mplayer -identify -vo null -ao null -frames 0 %f 2>&1 | sed -n '/^ID_/p' + + ### Play lists ### + + regex/\.([mM]3[uU]|[pP][lL][sS])$ +- Open=if [ -z "$DISPLAY" ]; then mplayer -vo null -playlist %f; else (xmms -p %f >/dev/null 2>&1 &); fi ++ Open=mplayer -vo null -playlist %f ++# Open=if [ -z "$DISPLAY" ]; then mplayer -vo null -playlist %f; else (xmms -p %f >/dev/null 2>&1 &); fi + + + ### Video ### +@@ -471,12 +486,12 @@ include/video + + # Postscript + type/^PostScript +- Open=(gv %f &) ++ Open=(xdg-open %f &) + View=%view{ascii} ps2ascii %f + + # PDF + type/^PDF +- Open=(xpdf %f &) ++ Open=(xdg-open %f &) + #Open=(acroread %f &) + #Open=(ghostview %f &) + View=%view{ascii} pdftotext %f - +@@ -486,7 +501,7 @@ type/^PDF + + # html + regex/\.([hH][tT][mM][lL]?)$ +- Open=(if test -n "@X11_WWW@" && test -n "$DISPLAY"; then (@X11_WWW@ file://%d/%p &) 1>&2; else links %f || lynx -force_html %f || ${PAGER:-more} %f; fi) 2>/dev/null ++ Open=xdg-open file://%d/%p 1>&2 + View=%view{ascii} links -dump %f 2>/dev/null || w3m -dump %f 2>/dev/null || lynx -dump -force_html %f + + # StarOffice 5.2 +@@ -504,22 +519,27 @@ shell/.abw + + # Microsoft Word Document + regex/\.([Dd][oO][cCtT]|[Ww][rR][iI])$ +- Open=(abiword %f >/dev/null 2>&1 &) ++ Open=(xdg-open %f &) ++# Open=(abiword %f >/dev/null 2>&1 &) + View=%view{ascii} antiword -t %f || catdoc -w %f || word2x -f text %f - || strings %f + type/^Microsoft\ Word +- Open=(abiword %f >/dev/null 2>&1 &) ++ Open=(xdg-open %f &) ++# Open=(abiword %f >/dev/null 2>&1 &) + View=%view{ascii} antiword -t %f || catdoc -w %f || word2x -f text %f - || strings %f + + # RTF document + regex/\.([rR][tT][fF])$ +- Open=(abiword %f >/dev/null 2>&1 &) ++ Open=(xdg-open %f &) ++# Open=(abiword %f >/dev/null 2>&1 &) + + # Microsoft Excel Worksheet + regex/\.([xX][lL][sSwW])$ +- Open=(gnumeric %f >/dev/null 2>&1 &) ++ Open=(xdg-open %f &) ++# Open=(gnumeric %f >/dev/null 2>&1 &) + View=%view{ascii} xls2csv %f || strings %f + type/^Microsoft\ Excel +- Open=(gnumeric %f >/dev/null 2>&1 &) ++ Open=(xdg-open %f &) ++# Open=(gnumeric %f >/dev/null 2>&1 &) + View=%view{ascii} xls2csv %f || strings %f + + # Use OpenOffice.org to open any MS Office documents diff --git a/mc-4.7.0.1-tty-slang.patch b/mc-4.7.0.1-tty-slang.patch new file mode 100644 index 0000000..5285ae3 --- /dev/null +++ b/mc-4.7.0.1-tty-slang.patch @@ -0,0 +1,11 @@ +--- mc-4.7.0-pre4.orig/src/tty/tty-slang.c 2009-11-07 16:29:08.000000000 0100 ++++ mc-4.7.0-pre4/src/tty/tty-slang.c 2009-11-07 16:28:50.000000000 +0100 +@@ -499,7 +499,7 @@ tty_set_alt_charset (gboolean alt_charse + void + tty_display_8bit (gboolean what) + { +- SLsmg_Display_Eight_Bit = what ? 128 : 160; ++ SLsmg_Display_Eight_Bit = what & xterm_flag ? 128 : 160; + } + + void diff --git a/mc-4.7.0.4-cross_compile_slang.patch b/mc-4.7.0.4-cross_compile_slang.patch new file mode 100644 index 0000000..a969991 --- /dev/null +++ b/mc-4.7.0.4-cross_compile_slang.patch @@ -0,0 +1,406 @@ +diff -Nru mc-4.7.0.4.orig//configure mc-4.7.0.4/configure +--- mc-4.7.0.4.orig//configure 2010-04-02 09:37:38.000000000 +0200 ++++ mc-4.7.0.4/configure 2010-04-12 00:43:23.076029038 +0200 +@@ -44838,66 +44838,7 @@ + if test x"$found_slang" = x"yes"; then + { $as_echo "$as_me:$LINENO: checking for S-Lang version 2.0 or newer" >&5 + $as_echo_n "checking for S-Lang version 2.0 or newer... " >&6; } +- if test "$cross_compiling" = yes; then +- mc_slang_is_valid_version=no +- +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-#ifdef HAVE_SLANG_SLANG_H +-#include +-#else +-#include +-#endif +-int main (void) +-{ +-#if SLANG_VERSION >= 20000 +- return 0; +-#else +- return 1; +-#endif +-} +- +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then +- mc_slang_is_valid_version=yes +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-( exit $ac_status ) +-mc_slang_is_valid_version=no +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi ++mc_slang_is_valid_version=yes + + + if test x$mc_slang_is_valid_version = xno; then +@@ -45407,66 +45348,8 @@ + if test x"$found_slang" = x"yes"; then + { $as_echo "$as_me:$LINENO: checking for S-Lang version 2.0 or newer" >&5 + $as_echo_n "checking for S-Lang version 2.0 or newer... " >&6; } +- if test "$cross_compiling" = yes; then +- mc_slang_is_valid_version=no +- +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-#ifdef HAVE_SLANG_SLANG_H +-#include +-#else +-#include +-#endif +-int main (void) +-{ +-#if SLANG_VERSION >= 20000 +- return 0; +-#else +- return 1; +-#endif +-} +- +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then + mc_slang_is_valid_version=yes +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 + +-( exit $ac_status ) +-mc_slang_is_valid_version=no +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi + + + if test x$mc_slang_is_valid_version = xno; then +@@ -45976,66 +45859,7 @@ + if test x"$found_slang" = x"yes"; then + { $as_echo "$as_me:$LINENO: checking for S-Lang version 2.0 or newer" >&5 + $as_echo_n "checking for S-Lang version 2.0 or newer... " >&6; } +- if test "$cross_compiling" = yes; then +- mc_slang_is_valid_version=no +- +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-#ifdef HAVE_SLANG_SLANG_H +-#include +-#else +-#include +-#endif +-int main (void) +-{ +-#if SLANG_VERSION >= 20000 +- return 0; +-#else +- return 1; +-#endif +-} +- +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then + mc_slang_is_valid_version=yes +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-( exit $ac_status ) +-mc_slang_is_valid_version=no +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi + + + if test x$mc_slang_is_valid_version = xno; then +@@ -47764,66 +47588,7 @@ + if test x"$found_slang" = x"yes"; then + { $as_echo "$as_me:$LINENO: checking for S-Lang version 2.0 or newer" >&5 + $as_echo_n "checking for S-Lang version 2.0 or newer... " >&6; } +- if test "$cross_compiling" = yes; then +- mc_slang_is_valid_version=no +- +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-#ifdef HAVE_SLANG_SLANG_H +-#include +-#else +-#include +-#endif +-int main (void) +-{ +-#if SLANG_VERSION >= 20000 +- return 0; +-#else +- return 1; +-#endif +-} +- +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then + mc_slang_is_valid_version=yes +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-( exit $ac_status ) +-mc_slang_is_valid_version=no +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi + + + if test x$mc_slang_is_valid_version = xno; then +@@ -48333,66 +48098,7 @@ + if test x"$found_slang" = x"yes"; then + { $as_echo "$as_me:$LINENO: checking for S-Lang version 2.0 or newer" >&5 + $as_echo_n "checking for S-Lang version 2.0 or newer... " >&6; } +- if test "$cross_compiling" = yes; then +- mc_slang_is_valid_version=no +- +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-#ifdef HAVE_SLANG_SLANG_H +-#include +-#else +-#include +-#endif +-int main (void) +-{ +-#if SLANG_VERSION >= 20000 +- return 0; +-#else +- return 1; +-#endif +-} +- +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then + mc_slang_is_valid_version=yes +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-( exit $ac_status ) +-mc_slang_is_valid_version=no +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi + + + if test x$mc_slang_is_valid_version = xno; then +@@ -48902,66 +48608,7 @@ + if test x"$found_slang" = x"yes"; then + { $as_echo "$as_me:$LINENO: checking for S-Lang version 2.0 or newer" >&5 + $as_echo_n "checking for S-Lang version 2.0 or newer... " >&6; } +- if test "$cross_compiling" = yes; then +- mc_slang_is_valid_version=no +- +-else +- cat >conftest.$ac_ext <<_ACEOF +-/* confdefs.h. */ +-_ACEOF +-cat confdefs.h >>conftest.$ac_ext +-cat >>conftest.$ac_ext <<_ACEOF +-/* end confdefs.h. */ +- +-#ifdef HAVE_SLANG_SLANG_H +-#include +-#else +-#include +-#endif +-int main (void) +-{ +-#if SLANG_VERSION >= 20000 +- return 0; +-#else +- return 1; +-#endif +-} +- +-_ACEOF +-rm -f conftest$ac_exeext +-if { (ac_try="$ac_link" +-case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_link") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); } && { ac_try='./conftest$ac_exeext' +- { (case "(($ac_try" in +- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; +- *) ac_try_echo=$ac_try;; +-esac +-eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" +-$as_echo "$ac_try_echo") >&5 +- (eval "$ac_try") 2>&5 +- ac_status=$? +- $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 +- (exit $ac_status); }; }; then + mc_slang_is_valid_version=yes +-else +- $as_echo "$as_me: program exited with status $ac_status" >&5 +-$as_echo "$as_me: failed program was:" >&5 +-sed 's/^/| /' conftest.$ac_ext >&5 +- +-( exit $ac_status ) +-mc_slang_is_valid_version=no +-fi +-rm -rf conftest.dSYM +-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +-fi + + + if test x$mc_slang_is_valid_version = xno; then diff --git a/mc-4.8.4-remember_file_position.patch b/mc-4.8.4-remember_file_position.patch new file mode 100644 index 0000000..2b99ed6 --- /dev/null +++ b/mc-4.8.4-remember_file_position.patch @@ -0,0 +1,53 @@ +Index: src/args.c +=================================================================== +--- src/args.c (revision 23c95d36ac4465627fbc9183e083a8320df77fcf) ++++ src/args.c (revision e39c697df47fe1beb727e0cb890a4c27c22cef09) +@@ -546,5 +546,5 @@ + else + { +- arg = mcedit_arg_vpath_new (tmp_vpath, 1); ++ arg = mcedit_arg_vpath_new (tmp_vpath, 0); + vfs_path_free (fname_vpath); + } +@@ -553,5 +553,5 @@ + } + else +- arg = mcedit_arg_new (tmp, 1); ++ arg = mcedit_arg_new (tmp, 0); + + flist = g_list_prepend (flist, arg); +@@ -559,12 +559,9 @@ + + if (flist == NULL) +- flist = g_list_prepend (flist, mcedit_arg_new (NULL, 1)); ++ flist = g_list_prepend (flist, mcedit_arg_new (NULL, 0)); + else if (first_line_number != -1) + { + /* overwrite line number for first file */ + GList *l; +- +- if (first_line_number == 0) +- first_line_number = 1; + + l = g_list_last (flist); +@@ -820,5 +817,5 @@ + * + * @param file_name file name +- * @param line_number line number ++ * @param line_number line number. If value is 0, try to restore saved position. + * @return mcedit_arg_t object + */ +@@ -835,5 +832,5 @@ + * + * @param file_vpath file path object +- * @param line_number line number ++ * @param line_number line number. If value is 0, try to restore saved position. + * @return mcedit_arg_t object + */ +@@ -846,6 +843,4 @@ + arg = g_new (mcedit_arg_t, 1); + arg->file_vpath = file_vpath; +- if (line_number == 0) +- line_number = 1; + arg->line_number = line_number; + diff --git a/mc.spec b/mc.spec new file mode 100644 index 0000000..5ab2a90 --- /dev/null +++ b/mc.spec @@ -0,0 +1,298 @@ +%define disable_X 0 +%define enable_vfs 1 + +Name: mc +Version: 4.8.12 +Release: 1mamba +Summary: A user-friendly file manager and visual shell +Group: Applications/Shells +Vendor: openmamba +Distribution: openmamba +Packager: Silvan Calarco +URL: http://www.midnight-commander.org +Source: http://www.midnight-commander.org/downloads/%{name}-%{version}.tar.xz +# see http://www.freedesktop.org/wiki/Software_2fBadSoftware +Patch1: %{name}-4.6.2-utf8.patch.gz +Patch5: %{name}-4.7.0.1-extensions.patch +Patch6: %{name}-4.7.0.1-tty-slang.patch +Patch7: %{name}-4.7.0.4-cross_compile_slang.patch +Patch8: mc-4.8.4-remember_file_position.patch +License: GPL +## AUTOBUILDREQ-BEGIN +BuildRequires: glibc-devel +BuildRequires: libglib-devel +%if "%{stage1}" != "1" +BuildRequires: libgpm-devel +%endif +BuildRequires: libslang-devel +BuildRequires: perl-devel +## AUTOBUILDREQ-END +BuildRequires: bison +BuildRequires: gettext +BuildRequires: unzip +BuildRequires: bash +BuildRequires: gettext-devel +BuildRequires: pkgconfig +BuildRequires: pam-devel +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description +Midnight Commander is a visual shell much like a file manager, only with way more features. +It is text mode, but also includes mouse support if you are running GPM. +Its coolest feature is the ability to ftp, view tar, zip files, and poke into RPMs for specific files. + +%prep +%setup -q -n %{name}-%{version} +#%patch1 -p1 +#%patch5 -p1 +#%patch6 -p1 +#%patch8 -p0 + +# FIXME: files in /lib should be converted to UTF-8 + +## convert man pages in /doc to UTF-8 +#cd doc/man +#for i in mc.1.in xnc.hlp; do +# iconv -f koi8-r -t utf-8 < ru/${i} > ru/${i}.tmp +# mv -f ru/${i}.tmp ru/${i} +#done +#for i in mc.1.in mcserv.8.in xnc.hlp; do +# iconv -f iso-8859-5 -t utf-8 < sr/${i} > sr/${i}.tmp +# mv -f sr/${i}.tmp sr/${i} +#done +#for d in es it; do +# for i in mc.1.in xnc.hlp; do +# iconv -f iso-8859-3 -t utf-8 < ${d}/${i} > ${d}/${i}.tmp +# mv -f ${d}/${i}.tmp ${d}/${i} +# done +#done +#for d in hu pl; do +# for i in mc.1.in xnc.hlp; do +# iconv -f iso-8859-2 -t utf-8 < ${d}/${i} > ${d}/${i}.tmp +# mv -f ${d}/${i}.tmp ${d}/${i} +# done +#done +#%if "%{_host}" != "%{_build}" +#%patch7 -p1 +#%endif + +%build +export CFLAGS="-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE %{optflags}" +#autoreconf +%configure \ + --enable-charset \ + --with-gpm-mouse \ + --with-screen=slang \ +%if "%{stage1}" != "1" + --with-samba \ +%endif + --disable-rpath \ +%if %enable_vfs + --enable-vfs-mcfs \ +%endif +%if %disable_X + --without-x \ +%endif +%if "%{_host}" != "%{_build}" + --with-slang-includes=/usr/%{_host}/include \ + --with-slang-libs=/usr/%{_host}/lib \ + CPPFLAGS="-lm -ldl" +%endif + +%make CFLAGS="%optflags -I%{_includedir}/slang" + +%install +[ "%{buildroot}" != / ] && rm -rf "%{buildroot}" +%if "%{_build}" != "%{_host}" +(cd src; rm -f man2hlp; gcc man2hlp.c -o man2hlp `pkg-config glib-2.0 --cflags --libs` -I..) +%endif + +%makeinstall + +# install profile files +install -d %{buildroot}%{_sysconfdir}/profile.d +install -m 755 contrib/{mc.sh,mc.csh} %{buildroot}%{_sysconfdir}/profile.d + +# install man pages in various languages +for lang in es hu it pl ru sr; do +mkdir -p %{buildroot}%{_mandir}/${lang} +mkdir -p %{buildroot}%{_mandir}/${lang}/man1 +gzip -nf9 doc/man/${lang}/mc.1 +install -m 644 doc/man/${lang}/mc.1.gz %{buildroot}%{_mandir}/${lang}/man1 +done + +%find_lang %{name} + +%clean +[ "%{buildroot}" != / ] && rm -rf "%{buildroot}" + +%files -f %{name}.lang +%defattr(-,root,root) +%{_sysconfdir}/mc/* +%{_bindir}/* +#%config %{_sysconfdir}/profile.d/* +%{_sysconfdir}/profile.d/*sh +%dir %{_datadir}/mc +%{_datadir}/mc/* +%dir %{_libexecdir}/mc +%{_libexecdir}/mc/cons.saver +%{_libexecdir}/mc/mc-wrapper.csh +%{_libexecdir}/mc/mc-wrapper.sh +%{_libexecdir}/mc/mc.csh +%{_libexecdir}/mc/mc.sh +%{_libexecdir}/mc/extfs.d +%{_libexecdir}/mc/fish +%dir %{_libexecdir}/mc/ext.d +%{_libexecdir}/mc/ext.d/*.sh +%{_mandir}/man1/* +%lang(es) %{_mandir}/es/man1/* +%lang(hu) %{_mandir}/hu/man1/* +%lang(it) %{_mandir}/it/man1/* +%lang(pl) %{_mandir}/pl/man1/* +%lang(ru) %{_mandir}/ru/man1/* +%lang(sr) %{_mandir}/sr/man1/* +%doc AUTHORS COPYING +#NEWS README* + +%changelog +* Tue Apr 01 2014 Automatic Build System 4.8.12-1mamba +- automatic version update by autodist + +* Mon Dec 02 2013 Automatic Build System 4.8.11-1mamba +- automatic version update by autodist + +* Thu Aug 15 2013 Automatic Build System 4.8.10-1mamba +- automatic update by autodist + +* Thu Jul 11 2013 Automatic Build System 4.8.9-1mamba +- automatic version update by autodist + +* Fri Apr 05 2013 Automatic Build System 4.8.8-1mamba +- automatic version update by autodist + +* Wed Jan 02 2013 Automatic Build System 4.8.7-1mamba +- automatic version update by autodist + +* Thu Oct 18 2012 Automatic Build System 4.8.6-1mamba +- automatic version update by autodist + +* Mon Sep 17 2012 Silvan Calarco 4.8.4-2mamba +- added an upstream patch to fix a regression in remembering mcedit file position (https://www.midnight-commander.org/ticket/2853?cversion=0&cnum_hist=4) +- re-enabled X11 events support + +* Fri Aug 17 2012 Automatic Build System 4.8.4-1mamba +- automatic version update by autodist + +* Thu Jul 19 2012 Automatic Build System 4.8.1.4-1mamba +- automatic version update by autodist + +* Thu Apr 26 2012 Automatic Build System 4.8.1.3-1mamba +- automatic version update by autodist + +* Sun Apr 22 2012 Automatic Build System 4.8.1.2-1mamba +- automatic version update by autodist + +* Tue Mar 20 2012 Automatic Build System 4.8.1.1-1mamba +- automatic version update by autodist + +* Wed Mar 14 2012 Automatic Build System 4.8.1-1mamba +- automatic version update by autodist + +* Mon Nov 14 2011 Automatic Build System 4.8.0-1mamba +- automatic version update by autodist + +* Sat Oct 01 2011 Automatic Build System 4.7.5.5-1mamba +- update to 4.7.5.5 + +* Thu Sep 15 2011 Automatic Build System 4.7.5.4-1mamba +- automatic version update by autodist + +* Mon Aug 01 2011 Automatic Build System 4.7.5.3-1mamba +- update to 4.7.5.3 + +* Mon Apr 11 2011 Automatic Build System 4.7.5.2-1mamba +- automatic update by autodist + +* Sun Feb 06 2011 Automatic Build System 4.7.5.1-1mamba +- automatic update by autodist + +* Tue Dec 28 2010 Automatic Build System 4.7.5-1mamba +- automatic update by autodist + +* Sun Nov 14 2010 Automatic Build System 4.7.4-1mamba +- automatic update by autodist + +* Mon Nov 08 2010 Automatic Build System 4.7.0.10-1mamba +- automatic update to 4.7.0.10 by autodist + +* Tue Sep 07 2010 Automatic Build System 4.7.0.9-1mamba +- automatic update to 4.7.0.9 by autodist + +* Sun Sep 05 2010 Automatic Build System 4.7.0.8-1mamba +- automatic update to 4.7.0.8 by autodist + +* Sun Jul 11 2010 Davide Madrisan 4.7.0.7-1mamba +- own %{_libexecdir}/mc +- update to 4.7.0.7 + +* Mon Apr 12 2010 Silvan Calarco 4.7.0.4-2mamba +- use standard make install + +* Sun Apr 11 2010 Silvan Calarco 4.7.0.4-1mamba +- update to 4.7.0.4 + +* Fri Mar 05 2010 Automatic Build System 4.7.0.3-1mamba +- automatic update to 4.7.0.3 by autodist + +* Wed Feb 10 2010 Automatic Build System 4.7.0.2-1mamba +- automatic update to 4.7.0.2 by autodist + +* Mon Jan 18 2010 Automatic Build System 4.7.0.1-1mamba +- automatic update to 4.7.0.1 by autodist + +* Mon Dec 07 2009 Silvan Calarco 4.6.2-2mamba +- added utf-8 patch for this version; rebuilt with X events support enabled + +* Mon Feb 02 2009 Silvan Calarco 4.6.2-1mamba +- update to 4.6.2 + +* Tue Dec 02 2008 Silvan Calarco 4.6.1-6mamba +- added bash32 and debian_fixes patches + +* Mon Dec 31 2007 Aleph0 4.6.1-5mamba +- fix permissions for profile files +- do not create insecure temporary files in mc-wrapper.[c]sh + +* Sat Aug 18 2007 Fabio Giani 4.6.1-4mamba +- specfile updates + +* Tue Jan 31 2006 Davide Madrisan 4.6.1-3qilnx +- enabled support for samba +- do use slang instead of mcslang +- converted to UTF-8 charset and install all the available man pages +- added missing build requirements + +* Wed Sep 14 2005 Silvan Calarco 4.6.1-2qilnx +- stable 4.6.1 version build + +* Mon May 02 2005 Davide Madrisan 4.6.1-1qilnx +- update from CVS +- also fixes security issues QSA-2005-059 + (CAN-2004-100[4,5,9], CAN-2004-109[0,1,2,3], CAN-2004-117[4,5,6]) + +* Tue May 18 2004 Davide Madrisan 4.6.0-5qilnx +- specfile updates + +* Mon May 03 2004 Davide Madrisan 4.6.0-4qilnx +- fixed CVE-CAN-2004-{0226,0231,0232} vulnerabilities + +* Wed Jan 28 2004 Davide Madrisan 4.6.0-3qilnx +- conditional disable_X flag +- /usr/lib/mc directory ownership + +* Wed Jan 21 2004 Davide Madrisan 4.6.0-2qilnx +- fixed CVE-CAN-2003-1023 vulnerability +- specfile updated + +* Mon Apr 14 2003 Alessandro Ramazzina +- creation of mc package