From b54155c4a4f354986c708328d97cb9e6a81d046d Mon Sep 17 00:00:00 2001 From: David Lawrence Ramsey Date: Wed, 12 Jan 2005 03:25:57 +0000 Subject: [PATCH] massive updates to multibyte/wide character support; deal with multibyte characters and strings instead of wide characters and strings as much as possible, and move multibyte/wide character-specific functions into their own source file, chars.c git-svn-id: svn://svn.savannah.gnu.org/nano/trunk/nano@2248 35c25a1d-7b9e-4130-9fde-d3aeb78583b8 --- ChangeLog | 20 + configure.ac | 8 +- src/Makefile.am | 3 +- src/chars.c | 352 ++++++++++++++++ src/files.c | 2 +- src/move.c | 4 +- src/nano.c | 127 +++--- src/nano.h | 13 +- src/proto.h | 51 ++- src/rcfile.c | 10 +- src/utils.c | 157 +------ src/winio.c | 1059 ++++++++++++++++++++--------------------------- 12 files changed, 947 insertions(+), 859 deletions(-) create mode 100644 src/chars.c diff --git a/ChangeLog b/ChangeLog index 48a16261..2258d3b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -87,6 +87,23 @@ CVS code - do_statusbar_input() and do_statusbar_output(); new functions keys_to_buffer(), unparse_kbinput(), and do_statusbar_verbatim_input(). (DLR) + - Yet more steps toward full wide character/multibyte character + support. Overhaul the functions that already have support for + them to work with multibyte strings as much as possible, add + support to a few more functions as well, and move multibyte + character-specific functions to their own source file. New + file chars.c; new functions is_blank_mbchar(), + is_blank_wchar(), is_cntrl_mbchar(), is_cntrl_wchar(), + control_mbrep(), control_wrep(), mbwidth(), mb_cur_max(), and + make_mbchar(); changes to is_blank_char() (moved to chars.c), + is_cntrl_char() (moved to chars.c), parse_char() (renamed + parse_mbchar() and moved to chars.c), do_verbatim_input(), + do_delete(), do_tab(), do_input(), do_output(), get_buffer(), + unget_input(), unget_kbinput(), get_input(), parse_kbinput(), + unparse_kbinput(), parse_verbatim_kbinput(), + do_statusbar_input(), do_statusbar_verbatim_kbinput(), + do_statusbar_output(), and display_string(); removal of + buffer_to_keys() and keys_to_buffer(). (DLR) - cut.c: do_cut_text() - If keep_cutbuffer is FALSE, only blow away the text in the @@ -209,6 +226,7 @@ CVS code - obsolete and it defines a struct termio that we don't use anywhere. (DLR) - Typo fixes. (DLR) + - Add checks for iswblank(), mblen(), and wctype.h. (DLR) - doc/faq.html: - Remove now-inaccurate note about verbatim input's not working at prompts, and update its description to mention that it @@ -219,6 +237,8 @@ CVS code - display. Since ASCII is technically only seven bits wide, characters 128-255 aren't ASCII. (DLR, suggested by Michael Piefel) +- src/Makefile.am: + - Add chars.c to nano_SOURCES. (DLR) GNU nano 1.3.5 - 2004.11.22 - General: diff --git a/configure.ac b/configure.ac index c9c0b649..399840c6 100644 --- a/configure.ac +++ b/configure.ac @@ -40,7 +40,7 @@ AM_GNU_GETTEXT([external], [need-ngettext]) dnl Checks for header files. AC_HEADER_STDC -AC_CHECK_HEADERS(fcntl.h getopt.h libintl.h limits.h regex.h termios.h wchar.h) +AC_CHECK_HEADERS(fcntl.h getopt.h libintl.h limits.h regex.h termios.h wchar.h wctype.h) AC_CHECK_HEADER(regex.h, AC_MSG_CHECKING([for broken regexec]) AC_TRY_RUN([ @@ -291,7 +291,7 @@ AC_MSG_WARN([*** Can not use slang when cross-compiling])), esac], [AC_MSG_RESULT(no)]) dnl Checks for functions -AC_CHECK_FUNCS(snprintf vsnprintf isblank strcasecmp strncasecmp strcasestr strnlen getline getdelim mbtowc wctomb wcwidth) +AC_CHECK_FUNCS(snprintf vsnprintf isblank iswblank strcasecmp strncasecmp strcasestr strnlen getline getdelim mblen mbtowc wctomb wcwidth) if test "x$ac_cv_func_snprintf" = "xno" -o "x$ac_cv_func_vsnprintf" = "xno" then AM_PATH_GLIB_2_0(2.0.0,, @@ -357,9 +357,9 @@ then LDFLAGS="$LDFLAGS $GLIB_LIBS" fi -if test "x$CURSES_LIB_WIDE" = "xyes" -a "x$ac_cv_func_mbtowc" = "xyes" -a "x$ac_cv_func_wctomb" = "xyes" -a "x$ac_cv_func_wcwidth" = "xyes" +if test "x$CURSES_LIB_WIDE" = "xyes" -a "x$ac_cv_func_mblen" = "xyes" -a "x$ac_cv_func_mbtowc" = "xyes" -a "x$ac_cv_func_wctomb" = "xyes" -a "x$ac_cv_func_wcwidth" = "xyes" then - AC_DEFINE(NANO_WIDE, 1, [Define this if your system has wide character support (a wide curses library, mbtowc(), wctomb(), and wcwidth()).]) + AC_DEFINE(NANO_WIDE, 1, [Define this if your system has wide character support (a wide curses library, mblen(), mbtowc(), wctomb(), and wcwidth()).]) else AC_MSG_WARN([Insufficient wide character support found. nano will not be able to support UTF-8.]) fi diff --git a/src/Makefile.am b/src/Makefile.am index 42a050a3..c47bb40c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,8 @@ INCLUDES = -Iintl -DLOCALEDIR=\"$(localedir)\" -DSYSCONFDIR=\"$(sysconfdir)\" ACLOCAL_AMFLAGS = -I m4 bin_PROGRAMS = nano -nano_SOURCES = color.c \ +nano_SOURCES = chars.c \ + color.c \ cut.c \ files.c \ global.c \ diff --git a/src/chars.c b/src/chars.c new file mode 100644 index 00000000..134bad3c --- /dev/null +++ b/src/chars.c @@ -0,0 +1,352 @@ +/* $Id$ */ +/************************************************************************** + * chars.c * + * * + * Copyright (C) 2005 Chris Allegretta * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2, or (at your option) * + * any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the Free Software * + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * + * * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include "proto.h" +#include "nano.h" + +#if defined(HAVE_WCHAR_H) && defined(NANO_WIDE) +#include +#endif + +#if defined(HAVE_WCTYPE_H) && defined(NANO_WIDE) +#include +#endif + +/* This function is equivalent to isblank(). */ +bool is_blank_char(unsigned char c) +{ + return +#ifdef HAVE_ISBLANK + isblank(c) +#else + isspace(c) && (c == '\t' || !is_cntrl_char(c)) +#endif + ; +} + +/* This function is equivalent to isblank() for multibyte characters. */ +bool is_blank_mbchar(const char *c) +{ + assert(c != NULL); + +#ifdef NANO_WIDE + if (!ISSET(NO_UTF8)) { + wchar_t wc; + int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX); + + if (c_mb_len <= 0) { + mbtowc(NULL, NULL, 0); + wc = (unsigned char)*c; + } + + return is_blank_wchar(wc); + } else +#endif + return is_blank_char((unsigned char)*c); +} + +#ifdef NANO_WIDE +/* This function is equivalent to isblank() for wide characters. */ +bool is_blank_wchar(wchar_t wc) +{ + return +#ifdef HAVE_ISWBLANK + iswblank(wc) +#else + iswspace(wc) && (wc == '\t' || !is_cntrl_wchar(wc)) +#endif + ; +} +#endif + +/* This function is equivalent to iscntrl(), except in that it also + * handles control characters with their high bits set. */ +bool is_cntrl_char(unsigned char c) +{ + return (c < 32) || (127 <= c && c < 160); +} + +/* This function is equivalent to iscntrl() for multibyte characters, + * except in that it also handles multibyte control characters with + * their high bits set. */ +bool is_cntrl_mbchar(const char *c) +{ + assert(c != NULL); + +#ifdef NANO_WIDE + if (!ISSET(NO_UTF8)) { + wchar_t wc; + int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX); + + if (c_mb_len <= 0) { + mbtowc(NULL, NULL, 0); + wc = (unsigned char)*c; + } + + return is_cntrl_wchar(wc); + } else +#endif + return is_cntrl_char((unsigned char)*c); +} + +#ifdef NANO_WIDE +/* This function is equivalent to iscntrl() for wide characters, except + * in that it also handles wide control characters with their high bits + * set. */ +bool is_cntrl_wchar(wchar_t wc) +{ + return (0 <= wc && wc < 32) || (127 <= wc && wc < 160); +} +#endif + +/* c is a control character. It displays as ^@, ^?, or ^[ch] where ch + * is c + 64. We return that character. */ +unsigned char control_rep(unsigned char c) +{ + /* Treat newlines embedded in a line as encoded nulls. */ + if (c == '\n') + return '@'; + else if (c == NANO_CONTROL_8) + return '?'; + else + return c + 64; +} + +/* c is a multibyte control character. It displays as ^@, ^?, or ^[ch] + * where ch is c + 64. We return that multibyte character. */ +char *control_mbrep(const char *c, char *crep, int *crep_len) +{ + assert(c != NULL); + +#ifdef NANO_WIDE + if (!ISSET(NO_UTF8)) { + wchar_t wc, wcrep; + int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX), crep_mb_len; + + if (c_mb_len <= 0) { + mbtowc(NULL, NULL, 0); + wc = *c; + } + + wcrep = control_wrep(wc); + + crep_mb_len = wctomb(crep, wcrep); + + if (crep_mb_len <= 0) { + wctomb(NULL, 0); + crep_mb_len = 0; + } + + *crep_len = crep_mb_len; + + return crep; + } else { +#endif + *crep_len = 1; + crep[0] = control_rep((unsigned char)*c); + + return crep; +#ifdef NANO_WIDE + } +#endif +} + +#ifdef NANO_WIDE +/* c is a wide control character. It displays as ^@, ^?, or ^[ch] where + * ch is c + 64. We return that wide character. */ +wchar_t control_wrep(wchar_t wc) +{ + /* Treat newlines embedded in a line as encoded nulls. */ + if (wc == '\n') + return '@'; + else if (wc == NANO_CONTROL_8) + return '?'; + else + return wc + 64; +} +#endif + +/* This function is equivalent to wcwidth() for multibyte characters. */ +int mbwidth(const char *c) +{ + assert(c != NULL); + +#ifdef NANO_WIDE + if (!ISSET(NO_UTF8)) { + wchar_t wc; + int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX), width; + + if (c_mb_len <= 0) { + mbtowc(NULL, NULL, 0); + wc = (unsigned char)*c; + } + + width = wcwidth(wc); + if (width == -1) + width++; + + return width; + } else +#endif + return 1; +} + +/* Return the maximum width in bytes of a multibyte character. */ +int mb_cur_max(void) +{ +#ifdef NANO_WIDE + if (!ISSET(NO_UTF8)) + return MB_CUR_MAX; + else +#endif + return 1; +} + +/* Convert the value in chr to a multibyte character with the same + * wide character value as chr. Return the multibyte character and its + * length. */ +char *make_mbchar(unsigned int chr, char *chr_mb, int *chr_mb_len) +{ +#ifdef NANO_WIDE + if (!ISSET(NO_UTF8)) { + *chr_mb_len = wctomb(chr_mb, chr); + + if (*chr_mb_len <= 0) { + mbtowc(NULL, NULL, 0); + *chr_mb_len = 1; + chr_mb[0] = (unsigned char)chr; + } + } else { +#endif + *chr_mb_len = 1; + chr_mb[0] = (unsigned char)chr; +#ifdef NANO_WIDE + } +#endif + + return chr_mb; +} + +/* Parse a multibyte character from buf. Return the number of bytes + * used. If chr isn't NULL, store the multibyte character in it. If + * bad_chr isn't NULL, set it to TRUE if we have a null byte or a bad + * multibyte character. If col isn't NULL, store the new display width + * in it. If *str is '\t', we expect col to have the current display + * width. */ +int parse_mbchar(const char *buf, char *chr +#ifdef NANO_WIDE + , bool *bad_chr +#endif + , size_t *col) +{ + int buf_mb_len; + + assert(buf != NULL); + +#ifdef NANO_WIDE + if (bad_chr != NULL) + *bad_chr = FALSE; + + if (!ISSET(NO_UTF8)) { + /* Get the number of bytes in the multibyte character. */ + buf_mb_len = mblen(buf, MB_CUR_MAX); + + /* If buf contains a null byte or an invalid multibyte + * character, interpret buf's first byte and set bad_chr to + * TRUE. */ + if (buf_mb_len <= 0) { + mblen(NULL, 0); + buf_mb_len = 1; + if (bad_chr != NULL) + *bad_chr = TRUE; + } + + /* Save the multibyte character in chr. */ + if (chr != NULL) { + int i; + for (i = 0; i < buf_mb_len; i++) + chr[i] = buf[i]; + } + + /* Save the column width of the wide character in col. */ + if (col != NULL) { + /* If we have a tab, get its width in columns using the + * current value of col. */ + if (*buf == '\t') + *col += tabsize - *col % tabsize; + /* If we have a control character, get its width using one + * column for the "^" that will be displayed in front of it, + * and the width in columns of its visible equivalent as + * returned by control_rep(). */ + else if (is_cntrl_mbchar(buf)) { + char *ctrl_buf_mb = charalloc(mb_cur_max()); + int ctrl_buf_mb_len; + + (*col)++; + + ctrl_buf_mb = control_mbrep(buf, ctrl_buf_mb, + &ctrl_buf_mb_len); + + *col += mbwidth(ctrl_buf_mb); + + free(ctrl_buf_mb); + /* If we have a normal character, get its width in columns + * normally. */ + } else + *col += mbwidth(buf); + } + } else { +#endif + /* Get the number of bytes in the byte character. */ + buf_mb_len = 1; + + /* Save the byte character in chr. */ + if (chr != NULL) + *chr = *buf; + + if (col != NULL) { + /* If we have a tab, get its width in columns using the + * current value of col. */ + if (*buf == '\t') + *col += tabsize - *col % tabsize; + /* If we have a control character, it's two columns wide: + * one column for the "^" that will be displayed in front of + * it, and one column for its visible equivalent as returned + * by control_rep(). */ + else if (is_cntrl_char((unsigned char)*buf)) + *col += 2; + /* If we have a normal character, it's one column wide. */ + else + (*col)++; + } +#ifdef NANO_WIDE + } +#endif + + return buf_mb_len; +} diff --git a/src/files.c b/src/files.c index 7598640b..96abdb27 100644 --- a/src/files.c +++ b/src/files.c @@ -2175,7 +2175,7 @@ char *input_tab(char *buf, int place, bool *lastwastab, int *newplace, tmp = matchbuf; /* skip any leading white space */ - while (*tmp && isblank(*tmp)) + while (*tmp && is_blank_char(*tmp)) ++tmp; /* Free up any memory already allocated */ diff --git a/src/move.c b/src/move.c index 72f346ef..73729030 100644 --- a/src/move.c +++ b/src/move.c @@ -2,7 +2,7 @@ /************************************************************************** * move.c * * * - * Copyright (C) 1999-2004 Chris Allegretta * + * Copyright (C) 1999-2005 Chris Allegretta * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2, or (at your option) * @@ -58,7 +58,7 @@ void do_home(void) if (ISSET(SMART_HOME)) { size_t current_x_save = current_x; - for (current_x = 0; isblank(current->data[current_x]) && + for (current_x = 0; is_blank_char(current->data[current_x]) && current->data[current_x] != '\0'; current_x++) ; diff --git a/src/nano.c b/src/nano.c index d8a78091..17e0567e 100644 --- a/src/nano.c +++ b/src/nano.c @@ -1144,8 +1144,9 @@ bool open_pipe(const char *command) void do_verbatim_input(void) { - int *kbinput; /* Used to hold verbatim input. */ - size_t kbinput_len; /* Length of verbatim input. */ + int *kbinput; + size_t kbinput_len, i; + char *output; statusbar(_("Verbatim input")); @@ -1153,9 +1154,15 @@ void do_verbatim_input(void) kbinput = get_verbatim_kbinput(edit, &kbinput_len); /* Display all the verbatim characters at once. */ - do_output(kbinput, kbinput_len); + output = charalloc(kbinput_len + 1); - free(kbinput); + for (i = 0; i < kbinput_len; i++) + output[i] = (char)kbinput[i]; + output[i] = '\0'; + + do_output(output, kbinput_len); + + free(output); } void do_backspace(void) @@ -1178,7 +1185,7 @@ void do_delete(void) placewewant = xplustabs(); if (current->data[current_x] != '\0') { - int char_len = parse_char(current->data + current_x, NULL + int char_buf_len = parse_mbchar(current->data + current_x, NULL #ifdef NANO_WIDE , NULL #endif @@ -1189,15 +1196,15 @@ void do_delete(void) /* Let's get dangerous. */ charmove(¤t->data[current_x], - ¤t->data[current_x + char_len], - line_len - char_len + 1); + ¤t->data[current_x + char_buf_len], + line_len - char_buf_len + 1); - null_at(¤t->data, current_x + line_len - char_len); + null_at(¤t->data, current_x + line_len - char_buf_len); #ifndef NANO_SMALL if (current_x < mark_beginx && mark_beginbuf == current) - mark_beginx -= char_len; + mark_beginx -= char_buf_len; #endif - totsize -= char_len; + totsize -= char_buf_len; } else if (current != filebot && (current->next != filebot || current->data[0] == '\0')) { /* We can delete the line before filebot only if it is blank: it @@ -1251,8 +1258,9 @@ void do_delete(void) void do_tab(void) { - int kbinput = '\t'; - do_output(&kbinput, 1); + char *kbinput = "\t"; + + do_output(kbinput, 1); } /* Someone hits return *gasp!* */ @@ -1455,7 +1463,7 @@ bool do_wrap(filestruct *inptr) wrap_line = inptr->data + i; for (; i < len; i++, wrap_line++) { /* Record where the last word ended. */ - if (!isblank(*wrap_line)) + if (!is_blank_char(*wrap_line)) word_back = i; /* If we have found a legal wrap point and the current word * extends too far, then we stop. */ @@ -1463,7 +1471,7 @@ bool do_wrap(filestruct *inptr) strnlenpt(inptr->data, word_back + 1) > fill) break; /* We record the latest legal wrap point. */ - if (word_back != i && !isblank(wrap_line[1])) + if (word_back != i && !is_blank_char(wrap_line[1])) wrap_loc = i; } if (i == len) @@ -1536,7 +1544,7 @@ bool do_wrap(filestruct *inptr) * between after_break and wrap_line. If the line already ends * in a tab or a space, we don't add a space and decrement * totsize to account for that. */ - if (!isblank(newline[new_line_len - 1])) + if (!is_blank_char(newline[new_line_len - 1])) strcat(newline, " "); else totsize--; @@ -2172,7 +2180,7 @@ size_t indent_length(const char *line) size_t len = 0; assert(line != NULL); - while (isblank(*line)) { + while (is_blank_char(*line)) { line++; len++; } @@ -2200,7 +2208,7 @@ void justify_format(filestruct *line, size_t skip) assert(line != NULL); assert(line->data != NULL); assert(skip < strlen(line->data)); - assert(!isblank(line->data[skip])); + assert(!is_blank_char(line->data[skip])); back = line->data + skip; for (front = back; ; front++) { @@ -2497,10 +2505,10 @@ bool breakable(const char *line, ssize_t goal) while (*line != '\0' && goal >= 0) { size_t pos = 0; - if (isblank(*line)) + if (is_blank_char(*line)) return TRUE; - line += parse_char(line, NULL + line += parse_mbchar(line, NULL #ifdef NANO_WIDE , NULL #endif @@ -2538,7 +2546,7 @@ ssize_t break_line(const char *line, ssize_t goal, bool force) assert(*line != '\t'); - line_len = parse_char(line, NULL + line_len = parse_mbchar(line, NULL #ifdef NANO_WIDE , NULL #endif @@ -3468,7 +3476,16 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool if (kbinput != NULL) { /* Display all the characters in the input buffer at * once. */ - do_output(kbinput, kbinput_len); + char *output = charalloc(kbinput_len + 1); + size_t i; + + for (i = 0; i < kbinput_len; i++) + output[i] = (char)kbinput[i]; + output[i] = '\0'; + + do_output(output, kbinput_len); + + free(output); /* Empty the input buffer. */ kbinput_len = 0; @@ -3588,55 +3605,45 @@ bool do_mouse(void) } #endif /* !DISABLE_MOUSE */ -/* The user typed kbinput_len wide characters. Add them to the edit - * buffer as multibyte characters. */ -void do_output(int *kbinput, size_t kbinput_len) +/* The user typed kbinput_len multibyte characters. Add them to the + * edit buffer. */ +void do_output(char *output, size_t output_len) { - size_t i, current_len = strlen(current->data); + size_t current_len = strlen(current->data), i = 0; bool old_constupdate = ISSET(CONSTUPDATE); bool do_refresh = FALSE; /* Do we have to call edit_refresh(), or can we get away with * update_line()? */ - char *key = -#ifdef NANO_WIDE - !ISSET(NO_UTF8) ? charalloc(MB_CUR_MAX) : -#endif - charalloc(1); + char *char_buf = charalloc(mb_cur_max()); + int char_buf_len; assert(current != NULL && current->data != NULL); /* Turn off constant cursor position display. */ UNSET(CONSTUPDATE); - for (i = 0; i < kbinput_len; i++) { - int key_len; - + while (i < output_len) { /* Null to newline, if needed. */ - if (kbinput[i] == '\0') - kbinput[i] = '\n'; + if (output[i] == '\0') + output[i] = '\n'; /* Newline to Enter, if needed. */ - else if (kbinput[i] == '\n') { + else if (output[i] == '\n') { do_enter(); + i++; continue; } + /* Interpret the next multibyte character. If it's an invalid + * multibyte character, interpret it as though it's a byte + * character. */ + char_buf_len = parse_mbchar(output + i, char_buf #ifdef NANO_WIDE - /* Change the wide character to its multibyte value. If it's - * invalid, go on to the next character. */ - if (!ISSET(NO_UTF8)) { - key_len = wctomb(key, (wchar_t)kbinput[i]); - - if (key_len == -1) - continue; - /* Interpret the character as a single-byte sequence. */ - } else { -#endif - key_len = 1; - key[0] = (unsigned char)kbinput[i]; -#ifdef NANO_WIDE - } + , NULL #endif + , NULL); + + i += char_buf_len; /* When a character is inserted on the current magicline, it * means we need a new one! */ @@ -3644,30 +3651,30 @@ void do_output(int *kbinput, size_t kbinput_len) new_magicline(); /* More dangerousness fun =) */ - current->data = charealloc(current->data, - current_len + (key_len * 2)); + current->data = charealloc(current->data, current_len + + (char_buf_len * 2)); assert(current_x <= current_len); - charmove(¤t->data[current_x + key_len], + charmove(¤t->data[current_x + char_buf_len], ¤t->data[current_x], - current_len - current_x + key_len); - charcpy(¤t->data[current_x], key, key_len); - current_len += key_len; - totsize += key_len; + current_len - current_x + char_buf_len); + charcpy(¤t->data[current_x], char_buf, char_buf_len); + current_len += char_buf_len; + totsize += char_buf_len; set_modified(); #ifndef NANO_SMALL /* Note that current_x has not yet been incremented. */ if (current == mark_beginbuf && current_x < mark_beginx) - mark_beginx += key_len; + mark_beginx += char_buf_len; #endif do_right(FALSE); #ifndef DISABLE_WRAPPING /* If we're wrapping text, we need to call edit_refresh(). */ - if (!ISSET(NO_WRAP) && kbinput[i] != '\t') { + if (!ISSET(NO_WRAP) && output[i] != '\t') { bool do_refresh_save = do_refresh; do_refresh = do_wrap(current); @@ -3692,7 +3699,7 @@ void do_output(int *kbinput, size_t kbinput_len) if (old_constupdate) SET(CONSTUPDATE); - free(key); + free(char_buf); if (do_refresh) edit_refresh(); diff --git a/src/nano.h b/src/nano.h index 21b23861..cd64b492 100644 --- a/src/nano.h +++ b/src/nano.h @@ -100,12 +100,8 @@ # endif #endif -/* If no isblank(), strcasecmp(), strncasecmp(), strcasestr(), - * strnlen(), getdelim(), or getline(), use the versions we have. */ -#ifndef HAVE_ISBLANK -#define isblank is_blank_char -#endif - +/* If no strcasecmp(), strncasecmp(), strcasestr(), strnlen(), + * getdelim(), or getline(), use the versions we have. */ #ifndef HAVE_STRCASECMP #define strcasecmp nstricmp #endif @@ -161,11 +157,6 @@ typedef enum { } topmidnone; /* Structure types. */ -typedef struct buffer { - int key; - bool key_code; -} buffer; - typedef struct filestruct { char *data; struct filestruct *next; /* Next node. */ diff --git a/src/proto.h b/src/proto.h index 7dc6ce79..2e4c768e 100644 --- a/src/proto.h +++ b/src/proto.h @@ -150,6 +150,31 @@ extern char *homedir; /* Functions we want available. */ +/* Public functions in chars.c. */ +bool is_blank_char(unsigned char c); +bool is_blank_mbchar(const char *c); +#ifdef NANO_WIDE +bool is_blank_wchar(wchar_t wc); +#endif +bool is_cntrl_char(unsigned char c); +bool is_cntrl_mbchar(const char *c); +#ifdef NANO_WIDE +bool is_cntrl_wchar(wchar_t wc); +#endif +unsigned char control_rep(unsigned char c); +char *control_mbrep(const char *c, char *crep, int *crep_len); +#ifdef NANO_WIDE +wchar_t control_wrep(wchar_t c); +#endif +int mbwidth(const char *c); +int mb_cur_max(void); +char *make_mbchar(unsigned int chr, char *chr_mb, int *chr_mb_len); +int parse_mbchar(const char *buf, char *chr +#ifdef NANO_WIDE + , bool *bad_chr +#endif + , size_t *col); + /* Public functions in color.c. */ #ifdef ENABLE_COLOR void set_colorpairs(void); @@ -396,7 +421,7 @@ int do_input(bool *meta_key, bool *func_key, bool *s_or_t, bool #ifndef DISABLE_MOUSE bool do_mouse(void); #endif -void do_output(int *kbinput, size_t kbinput_len); +void do_output(char *output, size_t output_len); /* Public functions in rcfile.c. */ #ifdef ENABLE_NANORC @@ -470,19 +495,9 @@ int regexec_safe(const regex_t *preg, const char *string, size_t nmatch, #endif int regexp_bol_or_eol(const regex_t *preg, const char *string); #endif -#ifndef HAVE_ISBLANK -int is_blank_char(int c); -#endif -int is_cntrl_char(int c); -bool is_byte_char(int c); int num_of_digits(int n); -unsigned char control_rep(unsigned char c); +bool is_byte(int c); bool parse_num(const char *str, ssize_t *val); -int parse_char(const char *buf, int *chr -#ifdef NANO_WIDE - , bool *bad_chr -#endif - , size_t *col); size_t move_left(const char *buf, size_t pos); size_t move_right(const char *buf, size_t pos); void align(char **strp); @@ -541,18 +556,16 @@ void reset_kbinput(void); #endif void get_buffer(WINDOW *win); size_t get_buffer_len(void); -int *buffer_to_keys(buffer *input, size_t input_len); -buffer *keys_to_buffer(int *input, size_t input_len); -void unget_input(buffer *input, size_t input_len); +void unget_input(int *input, size_t input_len); void unget_kbinput(int kbinput, bool meta_key, bool func_key); -buffer *get_input(WINDOW *win, size_t input_len); +int *get_input(WINDOW *win, size_t input_len); int get_kbinput(WINDOW *win, bool *meta_key, bool *func_key); int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key #ifndef NANO_SMALL , bool reset #endif ); -int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool +int get_escape_seq_kbinput(const int *seq, size_t seq_len, bool *ignore_seq); int get_escape_seq_abcd(int kbinput); int get_byte_kbinput(int kbinput @@ -566,7 +579,7 @@ int get_word_kbinput(int kbinput #endif ); int get_control_kbinput(int kbinput); -void unparse_kbinput(size_t pos, int *kbinput, size_t kbinput_len); +void unparse_kbinput(char *output, size_t output_len); int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len); int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len); #ifndef DISABLE_MOUSE @@ -590,7 +603,7 @@ void do_statusbar_backspace(void); void do_statusbar_delete(void); void do_statusbar_cut_text(void); void do_statusbar_verbatim_input(bool *got_enter); -void do_statusbar_output(int *kbinput, size_t kbinput_len, bool +void do_statusbar_output(char *output, size_t output_len, bool *got_enter); size_t xplustabs(void); size_t actual_x(const char *str, size_t xplus); diff --git a/src/rcfile.c b/src/rcfile.c index 8f1780cb..44b0b33e 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -126,7 +126,7 @@ void rcfile_error(const char *msg, ...) /* Parse the next word from the string. Returns NULL if we hit EOL. */ char *parse_next_word(char *ptr) { - while (!isblank(*ptr) && *ptr != '\n' && *ptr != '\0') + while (!is_blank_char(*ptr) && *ptr != '\n' && *ptr != '\0') ptr++; if (*ptr == '\0') @@ -135,7 +135,7 @@ char *parse_next_word(char *ptr) /* Null terminate and advance ptr */ *ptr++ = 0; - while (isblank(*ptr)) + while (is_blank_char(*ptr)) ptr++; return ptr; @@ -175,7 +175,7 @@ char *parse_argument(char *ptr) ptr = last_quote + 1; } if (ptr != NULL) - while (isblank(*ptr)) + while (is_blank_char(*ptr)) ptr++; return ptr; } @@ -233,7 +233,7 @@ char *parse_next_regex(char *ptr) /* Null terminate and advance ptr. */ *ptr++ = '\0'; - while (isblank(*ptr)) + while (is_blank_char(*ptr)) ptr++; return ptr; @@ -477,7 +477,7 @@ void parse_rcfile(FILE *rcstream) while (fgets(buf, 1023, rcstream) != 0) { lineno++; ptr = buf; - while (isblank(*ptr)) + while (is_blank_char(*ptr)) ptr++; if (*ptr == '\n' || *ptr == '\0') diff --git a/src/utils.c b/src/utils.c index dc95b95f..8ccfeecb 100644 --- a/src/utils.c +++ b/src/utils.c @@ -33,10 +33,6 @@ #include "proto.h" #include "nano.h" -#if defined(HAVE_WCHAR_H) && defined(NANO_WIDE) -#include -#endif - #ifdef HAVE_REGEX_H #ifdef BROKEN_REGEXEC int regexec_safe(const regex_t *preg, const char *string, size_t nmatch, @@ -56,29 +52,6 @@ int regexp_bol_or_eol(const regex_t *preg, const char *string) } #endif /* HAVE_REGEX_H */ -#ifndef HAVE_ISBLANK -/* This function is equivalent to isblank(). */ -int is_blank_char(int c) -{ - return isspace(c) && (!is_cntrl_char(c) || c == '\t'); -} -#endif - -/* This function is equivalent to iscntrl(), except in that it also - * handles control characters with their high bits set. */ -int is_cntrl_char(int c) -{ - return (-128 <= c && c < -96) || (0 <= c && c < 32) || - (127 <= c && c < 160); -} - -/* Return TRUE if the character c is in byte range, and FALSE - * otherwise. */ -bool is_byte_char(int c) -{ - return (unsigned int)c == (unsigned char)c; -} - int num_of_digits(int n) { int i = 1; @@ -94,17 +67,9 @@ int num_of_digits(int n) return i; } -/* c is a control character. It displays as ^@, ^?, or ^[ch] where ch - * is c + 64. We return that character. */ -unsigned char control_rep(unsigned char c) +bool is_byte(int c) { - /* Treat newlines embedded in a line as encoded nulls. */ - if (c == '\n') - return '@'; - else if (c == NANO_CONTROL_8) - return '?'; - else - return c + 64; + return ((unsigned int)c == (unsigned char)c); } /* Read a ssize_t from str, and store it in *val (if val is not NULL). @@ -128,116 +93,6 @@ bool parse_num(const char *str, ssize_t *val) return TRUE; } -/* Parse a multibyte character from buf. Return the number of bytes - * used. If chr isn't NULL, store the wide character in it. If - * bad_chr isn't NULL, set it to TRUE if we have a null byte or a bad - * multibyte character. If col isn't NULL, store the new display width - * in it. If *str is '\t', we expect col to have the current display - * width. */ -int parse_char(const char *buf, int *chr -#ifdef NANO_WIDE - , bool *bad_chr -#endif - , size_t *col) -{ - int wide_buf, mb_buf_len; - - assert(buf != NULL); - -#ifdef NANO_WIDE - if (bad_chr != NULL) - *bad_chr = FALSE; - - if (!ISSET(NO_UTF8)) { - wchar_t tmp; - - /* Get the wide character equivalent of the multibyte - * character. */ - mb_buf_len = mbtowc(&tmp, buf, MB_CUR_MAX); - wide_buf = (int)tmp; - - /* If buf contains a null byte or an invalid multibyte - * character, interpret buf's first byte as a single-byte - * sequence and set bad_chr to TRUE. */ - if (mb_buf_len <= 0) { - mb_buf_len = 1; - wide_buf = (unsigned char)*buf; - if (bad_chr != NULL) - *bad_chr = TRUE; - } - - /* Save the wide character in chr. */ - if (chr != NULL) - *chr = wide_buf; - - /* Save the column width of the wide character in col. */ - if (col != NULL) { - /* If we have a tab, get its width in columns using the - * current value of col. */ - if (wide_buf == '\t') - *col += tabsize - *col % tabsize; - /* If we have a control character, get its width using one - * column for the "^" that will be displayed in front of it, - * and the width in columns of its visible equivalent as - * returned by control_rep(). */ - else if (is_cntrl_char(wide_buf)) { - char *ctrl_mb_buf = charalloc(MB_CUR_MAX); - - (*col)++; - wide_buf = control_rep((unsigned char)wide_buf); - - if (wctomb(ctrl_mb_buf, (wchar_t)wide_buf) != -1) { - int width = wcwidth((wchar_t)wide_buf); - - if (width != -1) - *col += width; - } - else - (*col)++; - - free(ctrl_mb_buf); - /* If we have a normal character, get its width in columns - * normally. */ - } else { - int width = wcwidth((wchar_t)wide_buf); - - if (width != -1) - *col += width; - } - } - } else { -#endif - /* Interpret buf's first character as a single-byte sequence. */ - mb_buf_len = 1; - wide_buf = (unsigned char)*buf; - - /* Save the single-byte sequence in chr as though it's a wide - * character. */ - if (chr != NULL) - *chr = wide_buf; - - if (col != NULL) { - /* If we have a tab, get its width in columns using the - * current value of col. */ - if (wide_buf == '\t') - *col += tabsize - *col % tabsize; - /* If we have a control character, it's two columns wide: - * one column for the "^" that will be displayed in front of - * it, and one column for its visible equivalent as returned - * by control_rep(). */ - else if (is_cntrl_char(wide_buf)) - *col += 2; - /* If we have a normal character, it's one column wide. */ - else - (*col)++; - } -#ifdef NANO_WIDE - } -#endif - - return mb_buf_len; -} - /* Return the index in buf of the beginning of the character before the * one at pos. */ size_t move_left(const char *buf, size_t pos) @@ -249,16 +104,16 @@ size_t move_left(const char *buf, size_t pos) /* There is no library function to move backward one multibyte * character. Here is the naive, O(pos) way to do it. */ while (TRUE) { - int mb_buf_len = parse_char(buf + pos - pos_prev, NULL + int buf_mb_len = parse_mbchar(buf + pos - pos_prev, NULL #ifdef NANO_WIDE , NULL #endif , NULL); - if (pos_prev <= mb_buf_len) + if (pos_prev <= buf_mb_len) break; - pos_prev -= mb_buf_len; + pos_prev -= buf_mb_len; } return pos - pos_prev; @@ -268,7 +123,7 @@ size_t move_left(const char *buf, size_t pos) * one at pos. */ size_t move_right(const char *buf, size_t pos) { - return pos + parse_char(buf + pos, NULL + return pos + parse_mbchar(buf + pos, NULL #ifdef NANO_WIDE , NULL #endif diff --git a/src/winio.c b/src/winio.c index cb2df9af..3a99ea7d 100644 --- a/src/winio.c +++ b/src/winio.c @@ -32,11 +32,7 @@ #include "proto.h" #include "nano.h" -#if defined(HAVE_WCHAR_H) && defined(NANO_WIDE) -#include -#endif - -static buffer *key_buffer = NULL; +static int *key_buffer = NULL; /* The default keystroke buffer, * containing all the keystrokes we have * at a given point. */ @@ -131,32 +127,18 @@ void reset_kbinput(void) * default keystroke buffer is empty. */ void get_buffer(WINDOW *win) { - int input, input_key_code; + int input; /* If the keystroke buffer isn't empty, get out. */ if (key_buffer != NULL) return; /* Read in the first character using blocking input. */ - nodelay(win, FALSE); - #ifndef NANO_SMALL allow_pending_sigwinch(TRUE); #endif -#ifdef NANO_WIDE - if (!ISSET(NO_UTF8)) { - wint_t tmp; - - input_key_code = wget_wch(win, &tmp); - input = (int)tmp; - } else { -#endif - input = wgetch(win); - input_key_code = !is_byte_char(input); -#ifdef NANO_WIDE - } -#endif + input = wgetch(win); #ifndef NANO_SMALL allow_pending_sigwinch(FALSE); @@ -166,13 +148,8 @@ void get_buffer(WINDOW *win) * the keystroke in key, and set key_code to TRUE if the keystroke * is an extended keypad value or FALSE if it isn't. */ key_buffer_len++; - key_buffer = (buffer *)nmalloc(sizeof(buffer)); - key_buffer[0].key = input; - key_buffer[0].key_code = -#ifdef NANO_WIDE - !ISSET(NO_UTF8) ? (input_key_code == KEY_CODE_YES) : -#endif - input_key_code; + key_buffer = (int *)nmalloc(sizeof(int)); + key_buffer[0] = input; /* Read in the remaining characters using non-blocking input. */ nodelay(win, TRUE); @@ -182,25 +159,10 @@ void get_buffer(WINDOW *win) allow_pending_sigwinch(TRUE); #endif -#ifdef NANO_WIDE - if (!ISSET(NO_UTF8)) { - wint_t tmp; + input = wgetch(win); - input_key_code = wget_wch(win, &tmp); - input = (int)tmp; - } else { -#endif - input = wgetch(win); - input_key_code = !is_byte_char(input); -#ifdef NANO_WIDE - } -#endif /* If there aren't any more characters, stop reading. */ - if ( -#ifdef NANO_WIDE - (!ISSET(NO_UTF8) && input_key_code == ERR) || -#endif - input == ERR) + if (input == ERR) break; /* Otherwise, increment the length of the keystroke buffer, save @@ -208,14 +170,9 @@ void get_buffer(WINDOW *win) * if the keystroke is an extended keypad value or FALSE if it * isn't. */ key_buffer_len++; - key_buffer = (buffer *)nrealloc(key_buffer, key_buffer_len * - sizeof(buffer)); - key_buffer[key_buffer_len - 1].key = input; - key_buffer[key_buffer_len - 1].key_code = -#ifdef NANO_WIDE - !ISSET(NO_UTF8) ? (input_key_code == KEY_CODE_YES) : -#endif - input_key_code; + key_buffer = (int *)nrealloc(key_buffer, key_buffer_len * + sizeof(int)); + key_buffer[key_buffer_len - 1] = input; #ifndef NANO_SMALL allow_pending_sigwinch(FALSE); @@ -232,121 +189,57 @@ size_t get_buffer_len(void) return key_buffer_len; } -/* Return the key values stored in the keystroke buffer input, - * discarding the key_code values in it. */ -int *buffer_to_keys(buffer *input, size_t input_len) -{ - int *sequence = (int *)nmalloc(input_len * sizeof(int)); - size_t i; - - for (i = 0; i < input_len; i++) - sequence[i] = input[i].key; - - return sequence; -} - -/* Return the buffer equivalent of the key values in input, adding - * key_code values of FALSE to all of them. */ -buffer *keys_to_buffer(int *input, size_t input_len) -{ - buffer *sequence = (buffer *)nmalloc(input_len * sizeof(buffer)); - size_t i; - - for (i = 0; i < input_len; i++) { - sequence[i].key = input[i]; - sequence[i].key_code = FALSE; - } - - return sequence; -} - /* Add the contents of the keystroke buffer input to the default * keystroke buffer. */ -void unget_input(buffer *input, size_t input_len) +void unget_input(int *input, size_t input_len) { - buffer *clean_input = NULL; - size_t clean_input_len = 0; - #ifndef NANO_SMALL allow_pending_sigwinch(TRUE); allow_pending_sigwinch(FALSE); #endif -#ifdef NANO_WIDE - if (!ISSET(NO_UTF8)) { - size_t i; - char *key = charalloc(MB_CUR_MAX); - - /* Keep all valid wide keystrokes, discarding the others. */ - for (i = 0; i < input_len; i++) { - int key_len = input[i].key_code ? 1 : - wctomb(key, (wchar_t)input[i].key); - - if (key_len != -1) { - clean_input_len++; - clean_input = (buffer *)nrealloc(clean_input, - clean_input_len * sizeof(buffer)); - - clean_input[clean_input_len - 1].key = input[i].key; - clean_input[clean_input_len - 1].key_code = - input[i].key_code; - } - } - - free(key); - } else { -#endif - clean_input = input; - clean_input_len = input_len; -#ifdef NANO_WIDE - } -#endif - /* If input is empty, get out. */ - if (clean_input_len == 0) + if (input_len == 0) return; /* If adding input would put the default keystroke buffer beyond * maximum capacity, only add enough of input to put it at maximum * capacity. */ - if (key_buffer_len + clean_input_len < key_buffer_len) - clean_input_len = (size_t)-1 - key_buffer_len; + if (key_buffer_len + input_len < key_buffer_len) + input_len = (size_t)-1 - key_buffer_len; /* Add the length of input to the length of the default keystroke * buffer, and reallocate the default keystroke buffer so that it * has enough room for input. */ - key_buffer_len += clean_input_len; - key_buffer = (buffer *)nrealloc(key_buffer, key_buffer_len * - sizeof(buffer)); + key_buffer_len += input_len; + key_buffer = (int *)nrealloc(key_buffer, key_buffer_len * + sizeof(int)); /* If the default keystroke buffer wasn't empty before, move its * beginning forward far enough so that we can add input to its * beginning. */ - if (key_buffer_len > clean_input_len) - memmove(key_buffer + clean_input_len, key_buffer, - (key_buffer_len - clean_input_len) * sizeof(buffer)); + if (key_buffer_len > input_len) + memmove(key_buffer + input_len, key_buffer, + (key_buffer_len - input_len) * sizeof(int)); /* Copy input to the beginning of the default keystroke buffer. */ - memcpy(key_buffer, clean_input, clean_input_len * sizeof(buffer)); + memcpy(key_buffer, input, input_len * sizeof(int)); } -/* Put back the character stored in kbinput. If func_key is TRUE and - * the character is out of byte range, interpret it as an extended - * keypad value. If meta_key is TRUE, put back the Escape character - * after putting back kbinput. */ +/* Put back the character stored in kbinput, putting it in byte range + * beforehand. If meta_key is TRUE, put back the Escape character after + * putting back kbinput. If func_key is TRUE, put back the function key + * (a value outside byte range) without putting it in byte range. */ void unget_kbinput(int kbinput, bool meta_key, bool func_key) { - buffer input; - - input.key = kbinput; - input.key_code = (func_key && !is_byte_char(kbinput)); + if (!func_key) + kbinput = (char)kbinput; - unget_input(&input, 1); + unget_input(&kbinput, 1); if (meta_key) { - input.key = NANO_CONTROL_3; - input.key_code = FALSE; - unget_input(&input, 1); + kbinput = NANO_CONTROL_3; + unget_input(&kbinput, 1); } } @@ -355,9 +248,9 @@ void unget_kbinput(int kbinput, bool meta_key, bool func_key) * read in more characters from win and add them to the default * keystroke buffer before doing anything else. If the default * keystroke buffer is empty and win is NULL, return NULL. */ -buffer *get_input(WINDOW *win, size_t input_len) +int *get_input(WINDOW *win, size_t input_len) { - buffer *input; + int *input; #ifndef NANO_SMALL allow_pending_sigwinch(TRUE); @@ -382,11 +275,11 @@ buffer *get_input(WINDOW *win, size_t input_len) * buffer, and allocate the keystroke buffer input so that it * has enough room for input_len keystrokes. */ key_buffer_len -= input_len; - input = (buffer *)nmalloc(input_len * sizeof(buffer)); + input = (int *)nmalloc(input_len * sizeof(int)); /* Copy input_len characters from the beginning of the default * keystroke buffer into input. */ - memcpy(input, key_buffer, input_len * sizeof(buffer)); + memcpy(input, key_buffer, input_len * sizeof(int)); /* If the default keystroke buffer is empty, mark it as such. */ if (key_buffer_len == 0) { @@ -397,9 +290,9 @@ buffer *get_input(WINDOW *win, size_t input_len) * are no longer at its beginning. */ } else { memmove(key_buffer, key_buffer + input_len, key_buffer_len * - sizeof(buffer)); - key_buffer = (buffer *)nrealloc(key_buffer, key_buffer_len * - sizeof(buffer)); + sizeof(int)); + key_buffer = (int *)nrealloc(key_buffer, key_buffer_len * + sizeof(int)); } return input; @@ -441,8 +334,7 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key { static int escapes = 0, byte_digits = 0; - buffer *kbinput; - int retval = ERR; + int *kbinput, retval = ERR; #ifndef NANO_SMALL if (reset) { @@ -458,264 +350,258 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key /* Read in a character. */ while ((kbinput = get_input(win, 1)) == NULL); - if (kbinput->key_code || is_byte_char(kbinput->key)) { - /* If we got an extended keypad value or an ASCII character, - * translate it. */ - switch (kbinput->key) { - case ERR: - break; - case NANO_CONTROL_3: - /* Increment the escape counter. */ - escapes++; - switch (escapes) { - case 1: - /* One escape: wait for more input. */ - case 2: - /* Two escapes: wait for more input. */ - break; - default: - /* More than two escapes: reset the escape - * counter and wait for more input. */ - escapes = 0; - } - break; + switch (*kbinput) { + case ERR: + break; + case NANO_CONTROL_3: + /* Increment the escape counter. */ + escapes++; + switch (escapes) { + case 1: + /* One escape: wait for more input. */ + case 2: + /* Two escapes: wait for more input. */ + break; + default: + /* More than two escapes: reset the escape counter + * and wait for more input. */ + escapes = 0; + } + break; #if !defined(NANO_SMALL) && defined(KEY_RESIZE) - /* Since we don't change the default SIGWINCH handler when - * NANO_SMALL is defined, KEY_RESIZE is never generated. - * Also, Slang and SunOS 5.7-5.9 don't support - * KEY_RESIZE. */ - case KEY_RESIZE: - break; + /* Since we don't change the default SIGWINCH handler when + * NANO_SMALL is defined, KEY_RESIZE is never generated. Also, + * Slang and SunOS 5.7-5.9 don't support KEY_RESIZE. */ + case KEY_RESIZE: + break; #endif #ifdef PDCURSES - case KEY_SHIFT_L: - case KEY_SHIFT_R: - case KEY_CONTROL_L: - case KEY_CONTROL_R: - case KEY_ALT_L: - case KEY_ALT_R: - break; + case KEY_SHIFT_L: + case KEY_SHIFT_R: + case KEY_CONTROL_L: + case KEY_CONTROL_R: + case KEY_ALT_L: + case KEY_ALT_R: + break; #endif - default: - switch (escapes) { - case 0: - switch (kbinput->key) { - case NANO_CONTROL_8: - retval = ISSET(REBIND_DELETE) ? - NANO_DELETE_KEY : - NANO_BACKSPACE_KEY; - break; - case KEY_DOWN: - retval = NANO_NEXTLINE_KEY; - break; - case KEY_UP: - retval = NANO_PREVLINE_KEY; - break; - case KEY_LEFT: - retval = NANO_BACK_KEY; - break; - case KEY_RIGHT: - retval = NANO_FORWARD_KEY; - break; + default: + switch (escapes) { + case 0: + switch (*kbinput) { + case NANO_CONTROL_8: + retval = ISSET(REBIND_DELETE) ? + NANO_DELETE_KEY : NANO_BACKSPACE_KEY; + break; + case KEY_DOWN: + retval = NANO_NEXTLINE_KEY; + break; + case KEY_UP: + retval = NANO_PREVLINE_KEY; + break; + case KEY_LEFT: + retval = NANO_BACK_KEY; + break; + case KEY_RIGHT: + retval = NANO_FORWARD_KEY; + break; #ifdef KEY_HOME - /* HP-UX 10 and 11 don't support - * KEY_HOME. */ - case KEY_HOME: - retval = NANO_HOME_KEY; - break; + /* HP-UX 10 and 11 don't support KEY_HOME. */ + case KEY_HOME: + retval = NANO_HOME_KEY; + break; #endif - case KEY_BACKSPACE: - retval = NANO_BACKSPACE_KEY; - break; - case KEY_DC: - retval = ISSET(REBIND_DELETE) ? - NANO_BACKSPACE_KEY : - NANO_DELETE_KEY; - break; - case KEY_IC: - retval = NANO_INSERTFILE_KEY; - break; - case KEY_NPAGE: - retval = NANO_NEXTPAGE_KEY; - break; - case KEY_PPAGE: - retval = NANO_PREVPAGE_KEY; - break; - case KEY_ENTER: - retval = NANO_ENTER_KEY; - break; - case KEY_A1: /* Home (7) on numeric - * keypad with NumLock - * off. */ - retval = NANO_HOME_KEY; - break; - case KEY_A3: /* PageUp (9) on numeric - * keypad with NumLock - * off. */ - retval = NANO_PREVPAGE_KEY; - break; - case KEY_B2: /* Center (5) on numeric - * keypad with NumLock - * off. */ - break; - case KEY_C1: /* End (1) on numeric - * keypad with NumLock - * off. */ - retval = NANO_END_KEY; - break; - case KEY_C3: /* PageDown (4) on - * numeric keypad with - * NumLock off. */ - retval = NANO_NEXTPAGE_KEY; - break; + case KEY_BACKSPACE: + retval = NANO_BACKSPACE_KEY; + break; + case KEY_DC: + retval = ISSET(REBIND_DELETE) ? + NANO_BACKSPACE_KEY : NANO_DELETE_KEY; + break; + case KEY_IC: + retval = NANO_INSERTFILE_KEY; + break; + case KEY_NPAGE: + retval = NANO_NEXTPAGE_KEY; + break; + case KEY_PPAGE: + retval = NANO_PREVPAGE_KEY; + break; + case KEY_ENTER: + retval = NANO_ENTER_KEY; + break; + case KEY_A1: /* Home (7) on numeric keypad + * with NumLock off. */ + retval = NANO_HOME_KEY; + break; + case KEY_A3: /* PageUp (9) on numeric keypad + * with NumLock off. */ + retval = NANO_PREVPAGE_KEY; + break; + case KEY_B2: /* Center (5) on numeric keypad + * with NumLock off. */ + break; + case KEY_C1: /* End (1) on numeric keypad + * with NumLock off. */ + retval = NANO_END_KEY; + break; + case KEY_C3: /* PageDown (4) on numeric + * keypad with NumLock off. */ + retval = NANO_NEXTPAGE_KEY; + break; #ifdef KEY_BEG - /* Slang doesn't support KEY_BEG. */ - case KEY_BEG: /* Center (5) on numeric - * keypad with NumLock - * off. */ - break; + /* Slang doesn't support KEY_BEG. */ + case KEY_BEG: /* Center (5) on numeric keypad + * with NumLock off. */ + break; #endif #ifdef KEY_END - /* HP-UX 10 and 11 don't support KEY_END. */ - case KEY_END: - retval = NANO_END_KEY; - break; + /* HP-UX 10 and 11 don't support KEY_END. */ + case KEY_END: + retval = NANO_END_KEY; + break; #endif #ifdef KEY_SUSPEND - /* Slang doesn't support KEY_SUSPEND. */ - case KEY_SUSPEND: - retval = NANO_SUSPEND_KEY; - break; + /* Slang doesn't support KEY_SUSPEND. */ + case KEY_SUSPEND: + retval = NANO_SUSPEND_KEY; + break; #endif #ifdef KEY_SLEFT - /* Slang doesn't support KEY_SLEFT. */ - case KEY_SLEFT: - retval = NANO_BACK_KEY; - break; + /* Slang doesn't support KEY_SLEFT. */ + case KEY_SLEFT: + retval = NANO_BACK_KEY; + break; #endif #ifdef KEY_SRIGHT - /* Slang doesn't support KEY_SRIGHT. */ - case KEY_SRIGHT: - retval = NANO_FORWARD_KEY; - break; + /* Slang doesn't support KEY_SRIGHT. */ + case KEY_SRIGHT: + retval = NANO_FORWARD_KEY; + break; #endif - default: - retval = kbinput->key; - break; - } - break; - case 1: - /* One escape followed by a non-escape: escape - * sequence mode. Reset the escape counter. If - * there aren't any other keys waiting, we have - * a meta key sequence, so set meta_key to TRUE - * and save the lowercase version of the - * non-escape character as the result. If there - * are other keys waiting, we have a true escape - * sequence, so interpret it. */ - escapes = 0; - if (get_buffer_len() == 0) { - *meta_key = TRUE; - retval = tolower(kbinput->key); - } else { - buffer *escape_kbinput; - int *sequence; - size_t seq_len; - bool ignore_seq; - - /* Put back the non-escape character, get - * the complete escape sequence, translate - * the sequence into its corresponding key - * value, and save that as the result. */ - unget_input(kbinput, 1); - seq_len = get_buffer_len(); - escape_kbinput = get_input(NULL, seq_len); - sequence = buffer_to_keys(escape_kbinput, - seq_len); - retval = get_escape_seq_kbinput(sequence, - seq_len, &ignore_seq); - - /* If the escape sequence is unrecognized - * and not ignored, put back all of its - * characters except for the initial - * escape. */ - if (retval == ERR && !ignore_seq) - unget_input(escape_kbinput, seq_len); - - free(escape_kbinput); - } - break; - case 2: - /* Two escapes followed by one or more decimal - * digits: byte sequence mode. If the word - * sequence's range is limited to 2XX (the first - * digit is in the '0' to '2' range and it's the - * first digit, or it's in the '0' to '9' range - * and it's not the first digit), increment the - * byte sequence counter and interpret the - * digit. If the byte sequence's range is not - * limited to 2XX, fall through. */ - if (('0' <= kbinput->key && kbinput->key <= '6' - && byte_digits == 0) || - ('0' <= kbinput->key && kbinput->key <= '9' - && byte_digits > 0)) { - int byte_kbinput; - - byte_digits++; - byte_kbinput = get_byte_kbinput(kbinput->key + default: + retval = *kbinput; + break; + } + break; + case 1: + /* One escape followed by a non-escape: escape + * sequence mode. Reset the escape counter. If + * there aren't any other keys waiting, we have a + * meta key sequence, so set meta_key to TRUE and + * save the lowercase version of the non-escape + * character as the result. If there are other keys + * waiting, we have a true escape sequence, so + * interpret it. */ + escapes = 0; + if (get_buffer_len() == 0) { + *meta_key = TRUE; + retval = tolower(*kbinput); + } else { + int *seq; + size_t seq_len; + bool ignore_seq; + + /* Put back the non-escape character, get the + * complete escape sequence, translate the + * sequence into its corresponding key value, + * and save that as the result. */ + unget_input(kbinput, 1); + seq_len = get_buffer_len(); + seq = get_input(NULL, seq_len); + retval = get_escape_seq_kbinput(seq, seq_len, + &ignore_seq); + + /* If the escape sequence is unrecognized and + * not ignored, put back all of its characters + * except for the initial escape. */ + if (retval == ERR && !ignore_seq) + unget_input(seq, seq_len); + + free(seq); + } + break; + case 2: + /* Two escapes followed by one or more decimal + * digits: byte sequence mode. If the word + * sequence's range is limited to 2XX (the first + * digit is in the '0' to '2' range and it's the + * first digit, or it's in the '0' to '9' range and + * it's not the first digit), increment the byte + * sequence counter and interpret the digit. If the + * byte sequence's range is not limited to 2XX, fall + * through. */ + if (('0' <= *kbinput && *kbinput <= '6' && + byte_digits == 0) || ('0' <= *kbinput && + *kbinput <= '9' && byte_digits > 0)) { + int byte; + + byte_digits++; + byte = get_byte_kbinput(*kbinput #ifndef NANO_SMALL , FALSE #endif ); - if (byte_kbinput != ERR) { - /* If we've read in a complete byte - * sequence, reset the byte sequence - * counter and the escape counter, - * and put back the corresponding byte - * value. */ - byte_digits = 0; - escapes = 0; - unget_kbinput(byte_kbinput, FALSE, - FALSE); - } - } else { - /* Reset the escape counter. */ + if (byte != ERR) { + char *byte_mb = charalloc(mb_cur_max()); + int byte_mb_len, *seq, i; + + /* If we've read in a complete byte + * sequence, reset the byte sequence counter + * and the escape counter, and put back the + * corresponding byte value. */ + byte_digits = 0; escapes = 0; - if (byte_digits == 0) - /* Two escapes followed by a non-decimal - * digit or a decimal digit that would - * create a byte sequence greater than - * 2XX, and we're not in the middle of a - * byte sequence: control character - * sequence mode. Interpret the control - * sequence and save the corresponding - * control character as the result. */ - retval = get_control_kbinput(kbinput->key); - else { - /* If we're in the middle of a word - * sequence, reset the word sequence - * counter and save the character we got - * as the result. */ - byte_digits = 0; - retval = kbinput->key; - } + + /* Put back the multibyte equivalent of the + * byte value. */ + byte_mb = make_mbchar(byte, byte_mb, + &byte_mb_len); + + seq = (int *)nmalloc(byte_mb_len * + sizeof(int)); + + for (i = 0; i < byte_mb_len; i++) + seq[i] = (unsigned char)byte_mb[i]; + + unget_input(seq, byte_mb_len); + + free(seq); + free(byte_mb); } - break; - } - } + } else { + /* Reset the escape counter. */ + escapes = 0; + if (byte_digits == 0) + /* Two escapes followed by a non-decimal + * digit or a decimal digit that would + * create a byte sequence greater than 2XX, + * and we're not in the middle of a byte + * sequence: control character sequence + * mode. Interpret the control sequence and + * save the corresponding control character + * as the result. */ + retval = get_control_kbinput(*kbinput); + else { + /* If we're in the middle of a byte + * sequence, reset the byte sequence counter + * and save the character we got as the + * result. */ + byte_digits = 0; + retval = *kbinput; + } + } + break; + } + } - /* If we have a result and it's an extended keypad value, set - * func_key to TRUE. */ - if (retval != ERR) - *func_key = !is_byte_char(retval); - } else - /* If we didn't get an extended keypad value or an ASCII - * character, leave it as-is. */ - retval = kbinput->key; + /* If we have a result and it's an extended keypad value (i.e, a + * value outside of byte range), set func_key to TRUE. */ + if (retval != ERR) + *func_key = !is_byte(retval); #ifdef DEBUG - fprintf(stderr, "parse_kbinput(): kbinput->key = %d, meta_key = %d, func_key = %d, escapes = %d, byte_digits = %d, retval = %d\n", kbinput->key, (int)*meta_key, (int)*func_key, escapes, byte_digits, retval); + fprintf(stderr, "parse_kbinput(): kbinput = %d, meta_key = %d, func_key = %d, escapes = %d, byte_digits = %d, retval = %d\n", *kbinput, (int)*meta_key, (int)*func_key, escapes, byte_digits, retval); #endif /* Return the result. */ @@ -729,7 +615,7 @@ int parse_kbinput(WINDOW *win, bool *meta_key, bool *func_key * ERR and set ignore_seq to TRUE; if it's unrecognized, return ERR and * set ignore_seq to FALSE. Assume that Escape has already been read * in. */ -int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool +int get_escape_seq_kbinput(const int *seq, size_t seq_len, bool *ignore_seq) { int retval = ERR; @@ -737,12 +623,12 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool *ignore_seq = FALSE; if (seq_len > 1) { - switch (sequence[0]) { + switch (seq[0]) { case 'O': - switch (sequence[1]) { + switch (seq[1]) { case '2': if (seq_len >= 3) { - switch (sequence[2]) { + switch (seq[2]) { case 'P': /* Esc O 2 P == F13 on * xterm. */ retval = KEY_F(13); @@ -769,7 +655,7 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool * VT100/VT320/xterm. */ case 'D': /* Esc O D == Left on * VT100/VT320/xterm. */ - retval = get_escape_seq_abcd(sequence[1]); + retval = get_escape_seq_abcd(seq[1]); break; case 'E': /* Esc O E == Center (5) on numeric keypad * with NumLock off on xterm. */ @@ -824,7 +710,7 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool case 'b': /* Esc O b == Ctrl-Down on rxvt. */ case 'c': /* Esc O c == Ctrl-Right on rxvt. */ case 'd': /* Esc O d == Ctrl-Left on rxvt. */ - retval = get_escape_seq_abcd(sequence[1]); + retval = get_escape_seq_abcd(seq[1]); break; case 'j': /* Esc O j == '*' on numeric keypad with * NumLock off on VT100/VT220/VT320/xterm/ @@ -909,20 +795,20 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool } break; case 'o': - switch (sequence[1]) { + switch (seq[1]) { case 'a': /* Esc o a == Ctrl-Up on Eterm. */ case 'b': /* Esc o b == Ctrl-Down on Eterm. */ case 'c': /* Esc o c == Ctrl-Right on Eterm. */ case 'd': /* Esc o d == Ctrl-Left on Eterm. */ - retval = get_escape_seq_abcd(sequence[1]); + retval = get_escape_seq_abcd(seq[1]); break; } break; case '[': - switch (sequence[1]) { + switch (seq[1]) { case '1': if (seq_len >= 3) { - switch (sequence[2]) { + switch (seq[2]) { case '1': /* Esc [ 1 1 ~ == F1 on rxvt/ * Eterm. */ retval = KEY_F(1); @@ -960,10 +846,10 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool break; case ';': if (seq_len >= 4) { - switch (sequence[3]) { + switch (seq[3]) { case '2': if (seq_len >= 5) { - switch (sequence[4]) { + switch (seq[4]) { case 'A': /* Esc [ 1 ; 2 A == Shift-Up on * xterm. */ case 'B': /* Esc [ 1 ; 2 B == Shift-Down on @@ -972,14 +858,14 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool * xterm. */ case 'D': /* Esc [ 1 ; 2 D == Shift-Left on * xterm. */ - retval = get_escape_seq_abcd(sequence[4]); + retval = get_escape_seq_abcd(seq[4]); break; } } break; case '5': if (seq_len >= 5) { - switch (sequence[4]) { + switch (seq[4]) { case 'A': /* Esc [ 1 ; 5 A == Ctrl-Up on * xterm. */ case 'B': /* Esc [ 1 ; 5 B == Ctrl-Down on @@ -988,7 +874,7 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool * xterm. */ case 'D': /* Esc [ 1 ; 5 D == Ctrl-Left on * xterm. */ - retval = get_escape_seq_abcd(sequence[4]); + retval = get_escape_seq_abcd(seq[4]); break; } } @@ -1005,7 +891,7 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool break; case '2': if (seq_len >= 3) { - switch (sequence[2]) { + switch (seq[2]) { case '0': /* Esc [ 2 0 ~ == F9 on * VT220/VT320/Linux console/ * xterm/rxvt/Eterm. */ @@ -1096,7 +982,7 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool case 'D': /* Esc [ D == Left on ANSI/VT220/Linux * console/FreeBSD console/Mach console/ * rxvt/Eterm. */ - retval = get_escape_seq_abcd(sequence[1]); + retval = get_escape_seq_abcd(seq[1]); break; case 'E': /* Esc [ E == Center (5) on numeric keypad * with NumLock off on FreeBSD console. */ @@ -1130,7 +1016,7 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool break; case 'O': if (seq_len >= 3) { - switch (sequence[2]) { + switch (seq[2]) { case 'P': /* Esc [ O P == F1 on * xterm. */ retval = KEY_F(1); @@ -1191,11 +1077,11 @@ int get_escape_seq_kbinput(const int *sequence, size_t seq_len, bool case 'c': /* Esc [ c == Shift-Right on rxvt/ * Eterm. */ case 'd': /* Esc [ d == Shift-Left on rxvt/Eterm. */ - retval = get_escape_seq_abcd(sequence[1]); + retval = get_escape_seq_abcd(seq[1]); break; case '[': if (seq_len >= 3) { - switch (sequence[2]) { + switch (seq[2]) { case 'A': /* Esc [ [ A == F1 on Linux * console. */ retval = KEY_F(1); @@ -1258,13 +1144,13 @@ int get_byte_kbinput(int kbinput #endif ) { - static int byte_digits = 0, byte_kbinput = 0; + static int byte_digits = 0, byte = 0; int retval = ERR; #ifndef NANO_SMALL if (reset) { byte_digits = 0; - byte_kbinput = 0; + byte = 0; return ERR; } #endif @@ -1277,9 +1163,9 @@ int get_byte_kbinput(int kbinput /* One digit: reset the byte sequence holder and add the * digit we got to the 100's position of the byte sequence * holder. */ - byte_kbinput = 0; + byte = 0; if ('0' <= kbinput && kbinput <= '2') - byte_kbinput += (kbinput - '0') * 100; + byte += (kbinput - '0') * 100; else /* If the character we got isn't a decimal digit, or if * it is and it would put the byte sequence out of byte @@ -1289,10 +1175,9 @@ int get_byte_kbinput(int kbinput case 2: /* Two digits: add the digit we got to the 10's position of * the byte sequence holder. */ - if (('0' <= kbinput && kbinput <= '5') || - (byte_kbinput < 200 && '6' <= kbinput && - kbinput <= '9')) - byte_kbinput += (kbinput - '0') * 10; + if (('0' <= kbinput && kbinput <= '5') || (byte < 200 && + '6' <= kbinput && kbinput <= '9')) + byte += (kbinput - '0') * 10; else /* If the character we got isn't a decimal digit, or if * it is and it would put the byte sequence out of byte @@ -1303,11 +1188,10 @@ int get_byte_kbinput(int kbinput /* Three digits: add the digit we got to the 1's position of * the byte sequence holder, and save the corresponding word * value as the result. */ - if (('0' <= kbinput && kbinput <= '5') || - (byte_kbinput < 250 && '6' <= kbinput && - kbinput <= '9')) { - byte_kbinput += (kbinput - '0'); - retval = byte_kbinput; + if (('0' <= kbinput && kbinput <= '5') || (byte < 250 && + '6' <= kbinput && kbinput <= '9')) { + byte += (kbinput - '0'); + retval = byte; } else /* If the character we got isn't a decimal digit, or if * it is and it would put the word sequence out of word @@ -1325,11 +1209,11 @@ int get_byte_kbinput(int kbinput * sequence holder. */ if (retval != ERR) { byte_digits = 0; - byte_kbinput = 0; + byte = 0; } #ifdef DEBUG - fprintf(stderr, "get_byte_kbinput(): kbinput = %d, byte_digits = %d, byte_kbinput = %d, retval = %d\n", kbinput, byte_digits, byte_kbinput, retval); + fprintf(stderr, "get_byte_kbinput(): kbinput = %d, byte_digits = %d, byte = %d, retval = %d\n", kbinput, byte_digits, byte, retval); #endif return retval; @@ -1343,13 +1227,13 @@ int get_word_kbinput(int kbinput #endif ) { - static int word_digits = 0, word_kbinput = 0; + static int word_digits = 0, word = 0; int retval = ERR; #ifndef NANO_SMALL if (reset) { word_digits = 0; - word_kbinput = 0; + word = 0; return ERR; } #endif @@ -1362,11 +1246,11 @@ int get_word_kbinput(int kbinput /* One digit: reset the word sequence holder and add the * digit we got to the 4096's position of the word sequence * holder. */ - word_kbinput = 0; + word = 0; if ('0' <= kbinput && kbinput <= '9') - word_kbinput += (kbinput - '0') * 4096; + word += (kbinput - '0') * 4096; else if ('a' <= tolower(kbinput) && tolower(kbinput) <= 'f') - word_kbinput += (tolower(kbinput) + 10 - 'a') * 4096; + word += (tolower(kbinput) + 10 - 'a') * 4096; else /* If the character we got isn't a hexadecimal digit, or * if it is and it would put the word sequence out of @@ -1377,9 +1261,9 @@ int get_word_kbinput(int kbinput /* Two digits: add the digit we got to the 256's position of * the word sequence holder. */ if ('0' <= kbinput && kbinput <= '9') - word_kbinput += (kbinput - '0') * 256; + word += (kbinput - '0') * 256; else if ('a' <= tolower(kbinput) && tolower(kbinput) <= 'f') - word_kbinput += (tolower(kbinput) + 10 - 'a') * 256; + word += (tolower(kbinput) + 10 - 'a') * 256; else /* If the character we got isn't a hexadecimal digit, or * if it is and it would put the word sequence out of @@ -1390,9 +1274,9 @@ int get_word_kbinput(int kbinput /* Three digits: add the digit we got to the 16's position * of the word sequence holder. */ if ('0' <= kbinput && kbinput <= '9') - word_kbinput += (kbinput - '0') * 16; + word += (kbinput - '0') * 16; else if ('a' <= tolower(kbinput) && tolower(kbinput) <= 'f') - word_kbinput += (tolower(kbinput) + 10 - 'a') * 16; + word += (tolower(kbinput) + 10 - 'a') * 16; else /* If the character we got isn't a hexadecimal digit, or * if it is and it would put the word sequence out of @@ -1404,12 +1288,12 @@ int get_word_kbinput(int kbinput * the word sequence holder, and save the corresponding word * value as the result. */ if ('0' <= kbinput && kbinput <= '9') { - word_kbinput += (kbinput - '0'); - retval = word_kbinput; + word += (kbinput - '0'); + retval = word; } else if ('a' <= tolower(kbinput) && tolower(kbinput) <= 'f') { - word_kbinput += (tolower(kbinput) + 10 - 'a'); - retval = word_kbinput; + word += (tolower(kbinput) + 10 - 'a'); + retval = word; } else /* If the character we got isn't a hexadecimal digit, or * if it is and it would put the word sequence out of @@ -1427,11 +1311,11 @@ int get_word_kbinput(int kbinput * sequence holder. */ if (retval != ERR) { word_digits = 0; - word_kbinput = 0; + word = 0; } #ifdef DEBUG - fprintf(stderr, "get_word_kbinput(): kbinput = %d, word_digits = %d, word_kbinput = %d, retval = %d\n", kbinput, word_digits, word_kbinput, retval); + fprintf(stderr, "get_word_kbinput(): kbinput = %d, word_digits = %d, word = %d, retval = %d\n", kbinput, word_digits, word, retval); #endif return retval; @@ -1469,22 +1353,25 @@ int get_control_kbinput(int kbinput) return retval; } -/* Put the output-formatted key values in the input buffer kbinput back - * into the default keystroke buffer, starting at position pos, so that - * they can be parsed again. */ -void unparse_kbinput(size_t pos, int *kbinput, size_t kbinput_len) +/* Put the output-formatted characters in output back into the default + * keystroke buffer, so that they can be parsed and displayed as output + * again. */ +void unparse_kbinput(char *output, size_t output_len) { - if (pos < kbinput_len - 1) { - size_t seq_len = kbinput_len - (kbinput_len - pos); - buffer *sequence = keys_to_buffer(&kbinput[pos + 1], - seq_len); + int *input; + size_t i; - unget_input(sequence, seq_len); - free(sequence); - } + if (output_len == 0) + return; + + input = (int *)nmalloc(output_len * sizeof(int)); + for (i = 0; i < output_len; i++) + input[i] = (int)output[i]; + unget_input(input, output_len); + free(input); } -/* Read in a string of characters verbatim, and return the length of the +/* Read in a stream of characters verbatim, and return the length of the * string in kbinput_len. Assume nodelay(win) is FALSE. */ int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len) { @@ -1509,19 +1396,19 @@ int *get_verbatim_kbinput(WINDOW *win, size_t *kbinput_len) return retval; } -/* Read in a stream of all available characters. Translate the first - * few characters of the input into the corresponding word value if - * possible. After that, leave the input as-is. */ +/* Read in a stream of all available characters, and return the length + * of the string in kbinput_len. Translate the first few characters of + * the input into the corresponding word value if possible. After that, + * leave the input as-is. */ int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len) { - buffer *kbinput, *sequence; - int word, *retval; + int *kbinput, word, *retval; /* Read in the first keystroke. */ while ((kbinput = get_input(win, 1)) == NULL); /* Check whether the first keystroke is a hexadecimal digit. */ - word = get_word_kbinput(kbinput->key + word = get_word_kbinput(*kbinput #ifndef NANO_SMALL , FALSE #endif @@ -1534,30 +1421,37 @@ int *parse_verbatim_kbinput(WINDOW *win, size_t *kbinput_len) /* Otherwise, read in keystrokes until we have a complete word * sequence, and put back the corresponding word value. */ else { - buffer word_kbinput; + char *word_mb = charalloc(mb_cur_max()); + int word_mb_len, *seq, i; while (word == ERR) { while ((kbinput = get_input(win, 1)) == NULL); - word = get_word_kbinput(kbinput->key + word = get_word_kbinput(*kbinput #ifndef NANO_SMALL , FALSE #endif ); } - word_kbinput.key = word; - word_kbinput.key_code = FALSE; + /* Put back the multibyte equivalent of the word value. */ + word_mb = make_mbchar(word, word_mb, &word_mb_len); + + seq = (int *)nmalloc(word_mb_len * sizeof(int)); - unget_input(&word_kbinput, 1); + for (i = 0; i < word_mb_len; i++) + seq[i] = (unsigned char)word_mb[i]; + + unget_input(seq, word_mb_len); + + free(seq); + free(word_mb); } - /* Get the complete sequence, and save the key values in it as the + /* Get the complete sequence, and save the characters in it as the * result. */ *kbinput_len = get_buffer_len(); - sequence = get_input(NULL, *kbinput_len); - retval = buffer_to_keys(sequence, *kbinput_len); - free(sequence); + retval = get_input(NULL, *kbinput_len); return retval; } @@ -1787,12 +1681,21 @@ int do_statusbar_input(bool *meta_key, bool *func_key, bool *s_or_t, * characters in the input buffer if it isn't empty. */ if (*s_or_t == TRUE || get_buffer_len() == 0) { if (kbinput != NULL) { - bool got_enter; - /* Whether we got the Enter key. */ /* Display all the characters in the input buffer at * once. */ - do_statusbar_output(kbinput, kbinput_len, &got_enter); + char *output = charalloc(kbinput_len + 1); + size_t i; + bool got_enter; + /* Whether we got the Enter key. */ + + for (i = 0; i < kbinput_len; i++) + output[i] = (char)kbinput[i]; + output[i] = '\0'; + + do_statusbar_output(output, kbinput_len, &got_enter); + + free(output); /* Empty the input buffer. */ kbinput_len = 0; @@ -1900,7 +1803,7 @@ void do_statusbar_home(void) #ifndef NANO_SMALL if (ISSET(SMART_HOME)) { size_t statusbar_x_save = statusbar_x; - for (statusbar_x = 0; isblank(answer[statusbar_x]) && + for (statusbar_x = 0; is_blank_char(answer[statusbar_x]) && statusbar_x < statusbar_xend; statusbar_x++) ; if (statusbar_x == statusbar_x_save || @@ -1939,15 +1842,16 @@ void do_statusbar_backspace(void) void do_statusbar_delete(void) { if (statusbar_x < statusbar_xend) { - int char_len = parse_char(answer + statusbar_x, NULL + int char_buf_len = parse_mbchar(answer + statusbar_x, NULL #ifdef NANO_WIDE , NULL #endif , NULL); - charmove(answer + statusbar_x, answer + statusbar_x + char_len, - statusbar_xend - statusbar_x - char_len + 1); - statusbar_xend -= char_len; + charmove(answer + statusbar_x, answer + statusbar_x + + char_buf_len, statusbar_xend - statusbar_x - + char_buf_len + 1); + statusbar_xend -= char_buf_len; } } @@ -1960,8 +1864,9 @@ void do_statusbar_cut_text(void) void do_statusbar_verbatim_input(bool *got_enter) { - int *kbinput; /* Used to hold verbatim input. */ - size_t kbinput_len; /* Length of verbatim input. */ + int *kbinput; + size_t kbinput_len, i; + char *output; *got_enter = FALSE; @@ -1969,73 +1874,69 @@ void do_statusbar_verbatim_input(bool *got_enter) kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len); /* Display all the verbatim characters at once. */ - do_statusbar_output(kbinput, kbinput_len, got_enter); + output = charalloc(kbinput_len + 1); - free(kbinput); + for (i = 0; i < kbinput_len; i++) + output[i] = (char)kbinput[i]; + output[i] = '\0'; + + do_statusbar_output(output, kbinput_len, got_enter); + + free(output); } -void do_statusbar_output(int *kbinput, size_t kbinput_len, bool +void do_statusbar_output(char *output, size_t output_len, bool *got_enter) { - size_t i; + size_t i = 0; - char *key = -#ifdef NANO_WIDE - !ISSET(NO_UTF8) ? charalloc(MB_CUR_MAX) : -#endif - charalloc(1); + char *char_buf = charalloc(mb_cur_max()); + int char_buf_len; assert(answer != NULL); *got_enter = FALSE; - for (i = 0; i < kbinput_len; i++) { - int key_len; - + while (i < output_len) { /* Null to newline, if needed. */ - if (kbinput[i] == '\0') - kbinput[i] = '\n'; + if (output[i] == '\0') + output[i] = '\n'; /* Newline to Enter, if needed. */ - else if (kbinput[i] == '\n') { + else if (output[i] == '\n') { /* Set got_enter to TRUE to indicate that we got the Enter - * key, put back the rest of the keystrokes in kbinput so - * that they can be parsed again, and get out. */ + * key, put back the rest of the characters in output so + * that they can be parsed and output again, and get out. */ *got_enter = TRUE; - unparse_kbinput(i, kbinput, kbinput_len); + unparse_kbinput(output + i, output_len - i); return; } + /* Interpret the next multibyte character. If it's an invalid + * multibyte character, interpret it as though it's a byte + * character. */ + char_buf_len = parse_mbchar(output + i, char_buf #ifdef NANO_WIDE - /* Change the wide character to its multibyte value. If it's - * invalid, go on to the next character. */ - if (!ISSET(NO_UTF8)) { - key_len = wctomb(key, (wchar_t)kbinput[i]); - - if (key_len == -1) - continue; - /* Interpret the character as a single-byte sequence. */ - } else { -#endif - key_len = 1; - key[0] = (unsigned char)kbinput[i]; -#ifdef NANO_WIDE - } + , NULL #endif + , NULL); + + i += char_buf_len; /* More dangerousness fun =) */ - answer = charealloc(answer, statusbar_xend + key_len + 1); + answer = charealloc(answer, statusbar_xend + char_buf_len + 1); assert(statusbar_x <= statusbar_xend); - charmove(&answer[statusbar_x + key_len], &answer[statusbar_x], - statusbar_xend - statusbar_x + key_len); - charcpy(&answer[statusbar_x], key, key_len); - statusbar_xend += key_len; + charmove(&answer[statusbar_x + char_buf_len], + &answer[statusbar_x], statusbar_xend - statusbar_x + + char_buf_len); + charcpy(&answer[statusbar_x], char_buf, char_buf_len); + statusbar_xend += char_buf_len; do_statusbar_right(); } - free(key); + free(char_buf); } /* Return the placewewant associated with current_x. That is, xplustabs @@ -2059,7 +1960,7 @@ size_t actual_x(const char *str, size_t xplus) assert(str != NULL); while (*str != '\0') { - int str_len = parse_char(str, NULL + int str_len = parse_mbchar(str, NULL #ifdef NANO_WIDE , NULL #endif @@ -2088,7 +1989,7 @@ size_t strnlenpt(const char *str, size_t size) assert(str != NULL); while (*str != '\0') { - int str_len = parse_char(str, NULL + int str_len = parse_mbchar(str, NULL #ifdef NANO_WIDE , NULL #endif @@ -2170,6 +2071,12 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool size_t index; /* Current position in converted. */ + char *buf_mb = charalloc(mb_cur_max()); + int buf_mb_len; +#ifdef NANO_WIDE + bool bad_char; +#endif + /* If dollars is TRUE, make room for the "$" at the end of the * line. */ if (dollars && len > 0 && strlenpt(buf) > start_col + len) @@ -2183,92 +2090,59 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool assert(column <= start_col); -#ifdef NANO_WIDE - if (!ISSET(NO_UTF8)) - alloc_len = MB_CUR_MAX * (len + 2); - else -#endif - alloc_len = len + 2; + /* Allocate enough space for the entire line. It should contain + * (len + 2) multibyte characters at most. */ + alloc_len = mb_cur_max() * (len + 2); converted = charalloc(alloc_len + 1); index = 0; if (column < start_col || (dollars && column > 0 && buf[start_index] != '\t')) { - int wide_buf, mb_buf_len; - /* We don't display all of buf[start_index] since it starts to * the left of the screen. */ - mb_buf_len = parse_char(buf + start_index, &wide_buf + buf_mb_len = parse_mbchar(buf + start_index, buf_mb #ifdef NANO_WIDE , NULL #endif , NULL); - if (is_cntrl_char(wide_buf)) { + if (is_cntrl_mbchar(buf_mb)) { if (column < start_col) { - char *ctrl_mb_buf = -#ifdef NANO_WIDE - !ISSET(NO_UTF8) ? charalloc(MB_CUR_MAX) : -#endif - charalloc(1); - int ctrl_mb_buf_len, i; - - wide_buf = control_rep((unsigned char)wide_buf); - -#ifdef NANO_WIDE - if (!ISSET(NO_UTF8)) - ctrl_mb_buf_len = wctomb(ctrl_mb_buf, - (wchar_t)wide_buf); - else { -#endif - ctrl_mb_buf_len = 1; - ctrl_mb_buf[0] = (unsigned char)wide_buf; -#ifdef NANO_WIDE - } -#endif + char *ctrl_buf_mb = charalloc(mb_cur_max()); + int ctrl_buf_mb_len, i; - for (i = 0; i < ctrl_mb_buf_len; i++) - converted[index++] = ctrl_mb_buf[i]; + ctrl_buf_mb = control_mbrep(buf_mb, ctrl_buf_mb, + &ctrl_buf_mb_len); - free(ctrl_mb_buf); + for (i = 0; i < ctrl_buf_mb_len; i++) + converted[index++] = ctrl_buf_mb[i]; -#ifdef NANO_WIDE - if (!ISSET(NO_UTF8)) { - int width = wcwidth((wchar_t)wide_buf); + start_col += mbwidth(ctrl_buf_mb); - if (width != -1) - start_col += width; - } else -#endif - start_col++; + free(ctrl_buf_mb); - start_index += mb_buf_len; + start_index += buf_mb_len; } } #ifdef NANO_WIDE - else if (wcwidth((wchar_t)wide_buf) > 1) { + else if (mbwidth(buf_mb) > 1) { converted[index++] = ' '; - start_col++; - start_index += mb_buf_len; + + start_index += buf_mb_len; } #endif } while (index < alloc_len - 1 && buf[start_index] != '\0') { - int wide_buf, mb_buf_len; -#ifdef NANO_WIDE - bool bad_char; -#endif - - mb_buf_len = parse_char(buf + start_index, &wide_buf + buf_mb_len = parse_mbchar(buf + start_index, buf_mb #ifdef NANO_WIDE , &bad_char #endif , NULL); - if (wide_buf == '\t') { + if (*buf_mb == '\t') { converted[index++] = #if !defined(NANO_SMALL) && defined(ENABLE_NANORC) ISSET(WHITESPACE_DISPLAY) ? whitespace[0] : @@ -2282,45 +2156,23 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool /* If buf contains a control character, interpret it. If it * contains an invalid multibyte control character, interpret * that character as though it's a normal control character. */ - } else if (is_cntrl_char(wide_buf)) { - char *ctrl_mb_buf = -#ifdef NANO_WIDE - !ISSET(NO_UTF8) ? charalloc(MB_CUR_MAX) : -#endif - charalloc(1); - int ctrl_mb_buf_len, i; + } else if (is_cntrl_mbchar(buf_mb)) { + char *ctrl_buf_mb = charalloc(mb_cur_max()); + int ctrl_buf_mb_len, i; converted[index++] = '^'; start_col++; - wide_buf = control_rep((unsigned char)wide_buf); -#ifdef NANO_WIDE - if (!ISSET(NO_UTF8)) - ctrl_mb_buf_len = wctomb(ctrl_mb_buf, - (wchar_t)wide_buf); - else { -#endif - ctrl_mb_buf_len = 1; - ctrl_mb_buf[0] = (unsigned char)wide_buf; -#ifdef NANO_WIDE - } -#endif + ctrl_buf_mb = control_mbrep(buf_mb, ctrl_buf_mb, + &ctrl_buf_mb_len); - for (i = 0; i < ctrl_mb_buf_len; i++) - converted[index++] = ctrl_mb_buf[i]; + for (i = 0; i < ctrl_buf_mb_len; i++) + converted[index++] = ctrl_buf_mb[i]; - free(ctrl_mb_buf); + start_col += mbwidth(ctrl_buf_mb); -#ifdef NANO_WIDE - if (!ISSET(NO_UTF8)) { - int width = wcwidth((wchar_t)wide_buf); - - if (width != -1) - start_col += width; - } else -#endif - start_col++; - } else if (wide_buf == ' ') { + free(ctrl_buf_mb); + } else if (*buf_mb == ' ') { converted[index++] = #if !defined(NANO_SMALL) && defined(ENABLE_NANORC) ISSET(WHITESPACE_DISPLAY) ? whitespace[1] : @@ -2335,33 +2187,30 @@ char *display_string(const char *buf, size_t start_col, size_t len, bool * character, interpret that character as though it's a * normal non-control character. */ if (!ISSET(NO_UTF8) && bad_char) { - char *bad_mb_buf = charalloc(MB_CUR_MAX); - int bad_mb_buf_len; + char *bad_buf_mb = charalloc(mb_cur_max()); + int bad_buf_mb_len; + + bad_buf_mb = make_mbchar((unsigned int)*buf_mb, + bad_buf_mb, &bad_buf_mb_len); - bad_mb_buf_len = wctomb(bad_mb_buf, (wchar_t)wide_buf); + for (i = 0; i < bad_buf_mb_len; i++) + converted[index++] = bad_buf_mb[i]; - for (i = 0; i < bad_mb_buf_len; i++) - converted[index++] = bad_mb_buf[i]; + start_col += mbwidth(bad_buf_mb); - free(bad_mb_buf); + free(bad_buf_mb); } else { #endif - for (i = 0; i < mb_buf_len; i++) + for (i = 0; i < buf_mb_len; i++) converted[index++] = buf[start_index + i]; + + start_col += mbwidth(buf_mb); #ifdef NANO_WIDE } - - if (!ISSET(NO_UTF8)) { - int width = wcwidth((wchar_t)wide_buf); - - if (width != -1) - start_col += width; - } else #endif - start_col++; } - start_index += mb_buf_len; + start_index += buf_mb_len; } if (index < alloc_len - 1) -- 2.39.5