1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-12-04 14:46:47 -05:00

Merge with /srv/git/elinks.git

This commit is contained in:
Petr Baudis 2006-07-27 15:05:52 +02:00 committed by Petr Baudis
commit 3e2f7f48b5
61 changed files with 4337 additions and 1370 deletions

View File

@ -331,6 +331,9 @@ Len Lattanzi <Len_Lattanzi@StanfordAlumni.org>
M. K. Srikant <srix@vsnl.com>
Small fix in forms
M. Levinson <levinsm@users.sourceforge.net>
Python scripting fixes
Marco Bodrato <bodrato@linuz.sns.it>
Twinterm support
@ -420,6 +423,9 @@ Omar Khayam <omark@cyentec.com>
<otte@duke.edu>
Fix stdin reading on Mac OS X
Pavol Babincak <scroolik@gmail.com>
Improved UTF-8 support with double-width chars
Peder Stray <peder@ifi.uio.no>
Fix handling of key presses turning up as key prefixes

View File

@ -156,6 +156,7 @@ CONFIG_SPIDERMONKEY = @CONFIG_SPIDERMONKEY@
CONFIG_SSL = @CONFIG_SSL@
CONFIG_SYSMOUSE = @CONFIG_SYSMOUSE@
CONFIG_URI_REWRITE = @CONFIG_URI_REWRITE@
CONFIG_UTF_8 = @CONFIG_UTF_8@
CONFIG_XBEL_BOOKMARKS = @CONFIG_XBEL_BOOKMARKS@
CONFIG_XMLTO = @CONFIG_XMLTO@
CONFIG_GSSAPI = @CONFIG_GSSAPI@

View File

@ -19,7 +19,7 @@ AC_DEFUN([EL_LOG_CONFIG],
[msgdots2="`echo $about | sed 's/[0-9]/./g'`"]
[msgdots1="`echo $msgdots2 | sed 's/[a-z]/./g'`"]
[msgdots0="`echo $msgdots1 | sed 's/[A-Z]/./g'`"]
[msgdots="`echo $msgdots0 | sed 's/[_ ()]/./g'`"]
[msgdots="`echo $msgdots0 | sed 's/[-_ ()]/./g'`"]
DOTS="................................"
dots=`echo $DOTS | sed "s/$msgdots//"`

View File

@ -168,6 +168,7 @@ AC_HEADER_STDC
AC_HEADER_SYS_WAIT
AC_HEADER_TIME
AC_CHECK_HEADERS(wctype.h)
AC_CHECK_HEADERS(fcntl.h limits.h time.h unistd.h)
AC_CHECK_HEADERS(sigaction.h)
AC_CHECK_HEADERS(arpa/inet.h)
@ -770,17 +771,42 @@ dnl Check for Python
dnl ===================================================================
enable_python="no";
AC_ARG_WITH(python, [ --with-python=[prefix] enable Python support],
[
if test "$withval" != no; then
# FIXME: If withval is a valid directory append it to PATH
# so that you can specify one of several Python installations.
if test "$withval" != yes; then
python_prefix="$withval"
AC_ARG_WITH(python, [ --with-python=[DIR] enable Python support],
[ if test "x$withval" != xno; then enable_python=yes; fi ])
EL_SAVE_FLAGS
cf_result=no
AC_MSG_CHECKING([for Python])
if test "$enable_python" = "yes"; then
AC_MSG_RESULT(yes);
if test -d "$withval"; then
PYTHON_PATH="$withval:$PATH"
else
python_prefix=""
PYTHON_PATH="$PATH"
fi
enable_python=yes
AC_PATH_PROG(PYTHON, python, no, $PYTHON_PATH)
if test "$PYTHON" != no; then
cf_result="yes";
PYTHON_CFLAGS="`$PYTHON -c 'from distutils import sysconfig; print "-I%s -I%s" % (sysconfig.get_python_inc(), sysconfig.get_python_inc(plat_specific=True))'`"
PYTHON_LIBS="`$PYTHON -c 'from distutils import sysconfig; var = sysconfig.get_config_var; print "%s %s %s -L%s -lpython%s" % (var("LINKFORSHARED"), var("LIBS"), var("SYSLIBS"), var("LIBPL"), var("VERSION"))'`"
LIBS="$PYTHON_LIBS $LIBS"
CPPFLAGS="$CPPFLAGS $PYTHON_CFLAGS"
AC_TRY_LINK([#include <Python.h>],
[Py_Initialize();],
cf_result=yes, cf_result=no)
if test "$cf_result" != "yes"; then
EL_RESTORE_FLAGS
else
EL_CONFIG(CONFIG_SCRIPTING_PYTHON, [Python])
AC_SUBST(PYTHON_LIBS)
AC_SUBST(PYTHON_CFLAGS)
cat <<EOF
***********************************************************************
The Python support is incomplete and not so well integrated to ELinks
@ -790,48 +816,16 @@ well tested (success stories heartily welcomed!).
***********************************************************************
EOF
fi
])
cf_result=no
EL_SAVE_FLAGS
if test "$enable_python" = "yes"; then
if test -n "$python_prefix" && test -d "$python_prefix/bin"; then
PYTHON_PATH="$python_prefix/bin:$PATH"
else
PYTHON_PATH="$PATH"
fi
AC_PATH_PROG(PYTHON, python, no, $PYTHON_PATH)
if test "$PYTHON" = "no" ; then
cf_result=no
if test -n "$withval" && test "x$withval" != xno; then
AC_MSG_ERROR([Python not found])
else
PYTHON_CFLAGS="-I`$PYTHON -c 'from distutils import sysconfig; print sysconfig.get_python_inc()' 2> /dev/null`"
PYTHON_LIBS="-lpython`$PYTHON -c 'from distutils import sysconfig; print sysconfig.get_config_var("VERSION")' 2> /dev/null`"
if test -n "$python_prefix" && test -d "$python_prefix/lib"; then
PYTHON_LIBS="-L$python_prefix/lib $PYTHON_LIBS"
AC_MSG_WARN([Python support disabled])
fi
fi
LIBS="$PYTHON_LIBS $LIBS"
CFLAGS="$PYTHON_CFLAGS $CFLAGS"
AC_TRY_LINK([#include <Python.h>],
[Py_Initialize();],
cf_result=yes, cf_result=no)
if test "$cf_result" != "yes"; then
EL_RESTORE_FLAGS
else
EL_CONFIG(CONFIG_SCRIPTING_PYTHON, [Python])
CFLAGS="$CFLAGS_X"
AC_SUBST(PYTHON_LIBS)
AC_SUBST(PYTHON_CFLAGS)
AC_MSG_RESULT(no);
fi
fi
fi
AC_MSG_CHECKING([for Python])
if test "$cf_result"; then AC_MSG_RESULT($cf_result); fi
dnl ===================================================================
@ -1283,6 +1277,10 @@ EL_ARG_ENABLE(CONFIG_OWN_LIBC, own-libc, [Own libc stubs],
EL_ARG_ENABLE(CONFIG_SMALL, small, [Small binary],
[ --enable-small reduce binary size as far as possible (but see the bottom of doc/small.txt!)])
EL_ARG_ENABLE(CONFIG_UTF_8, utf-8, [UTF-8],
[ --enable-utf-8 enable UTF-8 support])
AC_ARG_ENABLE(weehoofooboomookerchoo,
[
Also check out the features.conf file for more information about features!
@ -1323,6 +1321,10 @@ AC_SUBST(CONFDIR)
# Create LOCALEDIR #define for config.h
LOCALEDIR=`eval echo "$datadir/locale"`
while echo "$LOCALEDIR" | grep "\\$"
do
LOCALEDIR=`eval echo "$LOCALEDIR"`
done > /dev/null 2> /dev/null
AC_DEFINE_UNQUOTED(LOCALEDIR, "$LOCALEDIR", [Directory containing locales])
AC_SUBST(LOCALEDIR)

View File

@ -1,13 +1,8 @@
If you want to use Python scripting with ELinks add
--with-python to the configure invocation copy hooks.py to ~/.elinks
When your Python installation is your own build, you could give prefix
to the configure, eg.
--with-python=/usr/local when Python binary is placed in /usr/local/bin, etc.
If you want to use Python scripting with ELinks, add --with-python to the
configure invocation and copy hooks.py to your ~/.elinks directory.
When 'configure' cannot find -lpython make symbolic link to the appropriate
library, eg.
# cd /usr/local/lib
# ln -s libpython2.4.so.1.0 libpython.so
If configure cannot find Python you can supply a path, e.g.
--with-python=/usr/local/bin if your Python binary is in /usr/local/bin, etc.
For the present hooks.py is not very usable. You are welcome to make it better.
Good Luck!

View File

@ -601,6 +601,27 @@ CONFIG_OWN_LIBC=no
CONFIG_SMALL=no
### Unicode UTF-8 support
#
# By enabling this option you get better Unicode support. At present only some
# parts of ELinks are influenced with this. It includes DOM, plain, HTML
# renderer and user interface. Beside normal Unicode characters there is
# support for double-width characters (like Japanese, etc.).
#
# Some features of Unicode are not handled at all. Combining characters is
# most visible absence.
# Some features are partially supported. Like line breaking between
# double-width characters. There is no other detection for determining when to
# break or not.
#
# Note: This UTF-8 support is experimental.
#
# Default: disabled
CONFIG_UTF_8=no
### Back-trace Printing
#
# Once upon a time, a disaster happens and ELinks crashes. That is a very sad

View File

@ -2802,7 +2802,7 @@ msgstr "Rozr
msgid ""
"Whether the search should match the document text while maintaining\n"
"case sensitivity."
msgstr "Czy zaznaczać tekst różniący się wielkością liter od poszukiwanego?"
msgstr "Czy rozróżniać wielkość liter przy szukaniu."
#: src/config/options.inc:393
msgid "Regular expressions"

View File

@ -77,17 +77,34 @@ add_dlg_button_do(struct dialog *dlg, unsigned char *text, int flags,
}
}
#ifdef CONFIG_UTF_8
static void
buttons_width(struct widget_data *widget_data, int n,
int *minwidth, int *maxwidth, int utf8)
#else
static void
buttons_width(struct widget_data *widget_data, int n,
int *minwidth, int *maxwidth)
#endif /* CONFIG_UTF_8 */
{
int maxw = -BUTTON_HSPACING;
#ifdef CONFIG_UTF_8
int button_lr_len = utf8_ptr2cells(BUTTON_LEFT, NULL)
+ utf8_ptr2cells(BUTTON_RIGHT, NULL);
#endif /* CONFIG_UTF_8 */
assert(n > 0);
if_assert_failed return;
while (n--) {
int minw = (widget_data++)->widget->info.button.textlen
int minw;
#ifdef CONFIG_UTF_8
if (utf8)
minw = utf8_ptr2cells((widget_data++)->widget->text, NULL)
+ BUTTON_HSPACING + button_lr_len;
else
#endif /* CONFIG_UTF_8 */
minw = (widget_data++)->widget->info.button.textlen
+ BUTTON_HSPACING + BUTTON_LR_LEN;
maxw += minw;
@ -100,7 +117,7 @@ buttons_width(struct widget_data *widget_data, int n,
void
dlg_format_buttons(struct terminal *term,
struct widget_data *widget_data, int n,
int x, int *y, int w, int *rw, enum format_align align)
int x, int *y, int w, int *rw, enum format_align align, int format_only)
{
int i1 = 0;
@ -111,20 +128,41 @@ dlg_format_buttons(struct terminal *term,
while (i2 < n) {
mw = 0;
#ifdef CONFIG_UTF_8
buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw,
term->utf8);
#else
buttons_width(widget_data1, i2 - i1 + 1, NULL, &mw);
#endif /* CONFIG_UTF_8 */
if (mw <= w) i2++;
else break;
}
mw = 0;
#ifdef CONFIG_UTF_8
buttons_width(widget_data1, i2 - i1, NULL, &mw, term->utf8);
#else
buttons_width(widget_data1, i2 - i1, NULL, &mw);
#endif /* CONFIG_UTF_8 */
if (rw) int_bounds(rw, mw, w);
if (term) {
if (!format_only) {
int i;
int p = x + (align == ALIGN_CENTER ? (w - mw) / 2 : 0);
#ifdef CONFIG_UTF_8
int button_lr_len = utf8_ptr2cells(BUTTON_LEFT, NULL)
+ utf8_ptr2cells(BUTTON_RIGHT, NULL);
#endif /* CONFIG_UTF_8 */
for (i = i1; i < i2; i++) {
#ifdef CONFIG_UTF_8
if (term->utf8)
set_box(&widget_data[i].box,
p, *y,
utf8_ptr2cells(widget_data[i].widget->text, NULL)
+ button_lr_len, BUTTON_HEIGHT);
else
#endif /* CONFIG_UTF_8 */
set_box(&widget_data[i].box,
p, *y,
widget_data[i].widget->info.button.textlen
@ -145,8 +183,7 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
struct terminal *term = dlg_data->win->term;
struct color_pair *color, *shortcut_color;
struct box *pos = &widget_data->box;
int len = widget_data->box.width - BUTTON_LR_LEN;
int x = pos->x + BUTTON_LEFT_LEN;
int len, x;
int sel = is_selected_widget(dlg_data, widget_data);
if (sel) {
@ -158,6 +195,23 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
}
if (!color || !shortcut_color) return EVENT_PROCESSED;
#ifdef CONFIG_UTF_8
if (term->utf8) {
int button_left_len = utf8_ptr2cells(BUTTON_LEFT, NULL);
int button_right_len = utf8_ptr2cells(BUTTON_RIGHT, NULL);
x = pos->x + button_left_len;
len = widget_data->box.width -
(button_left_len + button_right_len);
} else
#endif /* CONFIG_UTF_8 */
{
x = pos->x + BUTTON_LEFT_LEN;
len = widget_data->box.width - BUTTON_LR_LEN;
}
draw_text(term, pos->x, pos->y, BUTTON_LEFT, BUTTON_LEFT_LEN, 0, color);
if (len > 0) {
unsigned char *text = widget_data->widget->text;
@ -167,6 +221,52 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
attr = get_opt_bool("ui.dialogs.underline_button_shortcuts")
? SCREEN_ATTR_UNDERLINE : 0;
#ifdef CONFIG_UTF_8
if (term->utf8) {
if (hk_pos >= 0) {
int hk_bytes = utf8charlen(&text[hk_pos+1]);
int cells_to_hk = utf8_ptr2cells(text,
&text[hk_pos]);
int right = widget_data->widget->info.button.truetextlen
- hk_pos
- hk_bytes;
int hk_cells = utf8_char2cells(&text[hk_pos
+ 1],
NULL);
if (hk_pos)
draw_text(term, x, pos->y,
text, hk_pos, 0, color);
draw_text(term, x + cells_to_hk, pos->y,
&text[hk_pos + 1], hk_bytes,
attr, shortcut_color);
if (right > 1)
draw_text(term, x+cells_to_hk+hk_cells,
pos->y,
&text[hk_pos + hk_bytes + 1],
right - 1, 0, color);
} else {
int hk_width = utf8_char2cells(text, NULL);
int hk_len = utf8charlen(text);
int len_to_display =
utf8_cells2bytes(&text[hk_len],
len - hk_width,
NULL);
draw_text(term, x, pos->y,
text, hk_len,
attr, shortcut_color);
draw_text(term, x + hk_width, pos->y,
&text[hk_len], len_to_display,
0, color);
}
} else
#endif /* CONFIG_UTF_8 */
if (hk_pos >= 0) {
int right = widget_data->widget->info.button.truetextlen - hk_pos - 1;
@ -185,8 +285,17 @@ display_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
draw_text(term, x + 1, pos->y, &text[1], len - 1, 0, color);
}
}
draw_text(term, x + len, pos->y, BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color);
#ifdef CONFIG_UTF_8
if (term->utf8) {
int text_cells = utf8_ptr2cells(widget_data->widget->text, NULL);
int hk = (widget_data->widget->info.button.hotkey_pos >= 0);
draw_text(term, x + text_cells - hk, pos->y,
BUTTON_RIGHT, BUTTON_RIGHT_LEN, 0, color);
} else
#endif /* CONFIG_UTF_8 */
draw_text(term, x + len, pos->y, BUTTON_RIGHT,
BUTTON_RIGHT_LEN, 0, color);
if (sel) {
set_cursor(term, x, pos->y, 1);
set_window_ptr(dlg_data->win, pos->x, pos->y);

View File

@ -48,6 +48,6 @@ void add_dlg_button_do(struct dialog *dlg, unsigned char *text, int flags, widge
#endif
extern struct widget_ops button_ops;
void dlg_format_buttons(struct terminal *, struct widget_data *, int, int, int *, int, int *, enum format_align);
void dlg_format_buttons(struct terminal *, struct widget_data *, int, int, int *, int, int *, enum format_align, int);
#endif

View File

@ -39,7 +39,7 @@ void
dlg_format_checkbox(struct terminal *term,
struct widget_data *widget_data,
int x, int *y, int w, int *rw,
enum format_align align)
enum format_align align, int format_only)
{
unsigned char *text = widget_data->widget->text;
@ -52,7 +52,7 @@ dlg_format_checkbox(struct terminal *term,
dlg_format_text_do(term, text, x + CHECKBOX_LS, y,
w - CHECKBOX_LS, rw,
get_bfu_color(term, "dialog.checkbox-label"),
align);
align, format_only);
if (rw) *rw += CHECKBOX_LS;
}
}

View File

@ -33,7 +33,7 @@ void
dlg_format_checkbox(struct terminal *term,
struct widget_data *widget_data,
int x, int *y, int w, int *rw,
enum format_align align);
enum format_align align, int format_only);
#define widget_has_group(widget_data) ((widget_data)->widget->type == WIDGET_CHECKBOX \
? (widget_data)->widget->info.checkbox.gid : -1)

View File

@ -12,6 +12,7 @@
#include "bfu/dialog.h"
#include "config/kbdbind.h"
#include "config/options.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h"
#include "terminal/draw.h"
#include "main/timer.h"
@ -96,13 +97,32 @@ redraw_dialog(struct dialog_data *dlg_data, int layout)
title_color = get_bfu_color(term, "dialog.title");
if (title_color && box.width > 2) {
unsigned char *title = dlg_data->dlg->title;
int titlelen = int_min(box.width - 2, strlen(title));
int x = (box.width - titlelen) / 2 + box.x;
int y = box.y - 1;
int titlelen = strlen(title);
int titlecells = titlelen;
int x, y;
#ifdef CONFIG_UTF_8
if (term->utf8)
titlecells = utf8_ptr2cells(title,
&title[titlelen]);
#endif /* CONFIG_UTF_8 */
titlecells = int_min(box.width - 2, titlecells);
#ifdef CONFIG_UTF_8
if (term->utf8)
titlelen = utf8_cells2bytes(title, titlecells,
NULL);
#endif /* CONFIG_UTF_8 */
x = (box.width - titlecells) / 2 + box.x;
y = box.y - 1;
draw_text(term, x - 1, y, " ", 1, 0, title_color);
draw_text(term, x, y, title, titlelen, 0, title_color);
draw_text(term, x + titlelen, y, " ", 1, 0, title_color);
draw_text(term, x + titlecells, y, " ", 1, 0,
title_color);
}
}
@ -499,7 +519,7 @@ clear_dialog(struct dialog_data *dlg_data, struct widget_data *xxx)
static void
format_widgets(struct terminal *term, struct dialog_data *dlg_data,
int x, int *y, int w, int h, int *rw)
int x, int *y, int w, int h, int *rw, int format_only)
{
struct widget_data *wdata = dlg_data->widgets_data;
int widgets = dlg_data->number_of_widgets;
@ -509,15 +529,18 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
switch (wdata->widget->type) {
case WIDGET_FIELD_PASS:
case WIDGET_FIELD:
dlg_format_field(term, wdata, x, y, w, rw, ALIGN_LEFT);
dlg_format_field(term, wdata, x, y, w, rw, ALIGN_LEFT,
format_only);
break;
case WIDGET_LISTBOX:
dlg_format_listbox(term, wdata, x, y, w, h, rw, ALIGN_LEFT);
dlg_format_listbox(term, wdata, x, y, w, h, rw,
ALIGN_LEFT, format_only);
break;
case WIDGET_TEXT:
dlg_format_text(term, wdata, x, y, w, rw, h);
dlg_format_text(term, wdata, x, y, w, rw, h,
format_only);
break;
case WIDGET_CHECKBOX:
@ -535,14 +558,16 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
break;
}
dlg_format_group(term, wdata, size, x, y, w, rw);
dlg_format_group(term, wdata, size, x, y, w, rw,
format_only);
wdata += size - 1;
} else {
/* No horizontal space between checkboxes belonging to
* the same group. */
dlg_format_checkbox(term, wdata, x, y, w, rw, ALIGN_LEFT);
dlg_format_checkbox(term, wdata, x, y, w, rw,
ALIGN_LEFT, format_only);
if (widgets > 1
&& group == widget_has_group(&wdata[1]))
(*y)--;
@ -554,7 +579,7 @@ format_widgets(struct terminal *term, struct dialog_data *dlg_data,
* of the dialog. */
case WIDGET_BUTTON:
dlg_format_buttons(term, wdata, widgets,
x, y, w, rw, ALIGN_CENTER);
x, y, w, rw, ALIGN_CENTER, format_only);
return;
}
}
@ -566,11 +591,17 @@ generic_dialog_layouter(struct dialog_data *dlg_data)
struct terminal *term = dlg_data->win->term;
int w = dialog_max_width(term);
int height = dialog_max_height(term);
int rw = int_min(w, strlen(dlg_data->dlg->title));
int y = dlg_data->dlg->layout.padding_top ? 0 : -1;
int x = 0;
int x = 0, y, rw;
format_widgets(NULL, dlg_data, x, &y, w, height, &rw);
#ifdef CONFIG_UTF_8
if (term->utf8)
rw = int_min(w, utf8_ptr2cells(dlg_data->dlg->title, NULL));
else
#endif /* CONFIG_UTF_8 */
rw = int_min(w, strlen(dlg_data->dlg->title));
y = dlg_data->dlg->layout.padding_top ? 0 : -1;
format_widgets(term, dlg_data, x, &y, w, height, &rw, 1);
/* Update the width to respond to the required minimum width */
if (dlg_data->dlg->layout.fit_datalen) {
@ -585,7 +616,7 @@ generic_dialog_layouter(struct dialog_data *dlg_data)
y = dlg_data->box.y + DIALOG_TB + dlg_data->dlg->layout.padding_top;
x = dlg_data->box.x + DIALOG_LB;
format_widgets(term, dlg_data, x, &y, w, height, NULL);
format_widgets(term, dlg_data, x, &y, w, height, NULL, 0);
}
@ -607,7 +638,15 @@ draw_dialog(struct dialog_data *dlg_data, int width, int height)
/* Draw shadow */
draw_shadow(term, &dlg_data->box,
get_bfu_color(term, "dialog.shadow"), 2, 1);
#ifdef CONFIG_UTF_8
if (term->utf8)
fix_dwchar_around_box(term, &dlg_data->box, 0, 2, 1);
#endif /* CONFIG_UTF_8 */
}
#ifdef CONFIG_UTF_8
else if(term->utf8)
fix_dwchar_around_box(term, &dlg_data->box, 0, 0, 0);
#endif /* CONFIG_UTF_8 */
}
static void

View File

@ -16,10 +16,13 @@
#include "terminal/terminal.h"
#include "util/color.h"
/* Same as in src/bfu/checkbox.c */
#define CHECKBOX_LEN 3 /* "[X]" or "(X)" */
void
dlg_format_group(struct terminal *term,
struct widget_data *widget_data,
int n, int x, int *y, int w, int *rw)
int n, int x, int *y, int w, int *rw, int format_only)
{
int space_between_widgets = 1;
int line_width = 0;
@ -33,12 +36,30 @@ dlg_format_group(struct terminal *term,
int widget_width;
int width;
unsigned char *text = widget_data->widget->text;
int label_length = (text && *text) ? strlen(text) : 0;
int label_padding = (label_length > 0);
int label_length;
int label_padding;
#ifdef CONFIG_UTF_8
if (term->utf8) {
if (text && *text)
label_length = utf8_ptr2cells(text, NULL);
else
label_length = 0;
} else
#endif /* CONFIG_UTF_8 */
label_length = (text && *text) ? strlen(text) : 0;
label_padding = (label_length > 0);
if (widget_data->widget->type == WIDGET_CHECKBOX) {
width = 3;
width = CHECKBOX_LEN;
} else if (widget_is_textfield(widget_data)) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
width = utf8_ptr2cells(widget_data->widget->data,
NULL);
} else
#endif /* CONFIG_UTF_8 */
width = widget_data->widget->datalen;
} else {
/* TODO: handle all widget types. */
@ -56,22 +77,52 @@ dlg_format_group(struct terminal *term,
xpos = x + line_width;
if (term) {
if (!format_only) {
if (widget_data->widget->type == WIDGET_CHECKBOX) {
/* Draw text at right of checkbox. */
if (label_length)
draw_text(term, xpos + width + label_padding, *y,
text, label_length,
0, color);
if (label_length) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
int lb = utf8_cells2bytes(
text,
label_length,
NULL);
draw_text(term, xpos + width
+ label_padding,
*y, text, lb, 0,
color);
} else
#endif /* CONFIG_UTF_8 */
{
draw_text(term, xpos + width
+ label_padding,
*y, text,
label_length, 0,
color);
}
}
set_box(&widget_data->box, xpos, *y, width, 1);
} else if (widget_is_textfield(widget_data)) {
/* Draw label at left of widget. */
if (label_length)
if (label_length) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
int lb = utf8_cells2bytes(
text,
label_length,
NULL);
draw_text(term, xpos, *y,
text, lb, 0, color);
} else
#endif /* CONFIG_UTF_8 */
{
draw_text(term, xpos, *y,
text, label_length,
0, color);
}
}
set_box(&widget_data->box,
xpos + label_padding + label_length, *y,
@ -93,16 +144,23 @@ group_layouter(struct dialog_data *dlg_data)
{
struct terminal *term = dlg_data->win->term;
int w = dialog_max_width(term);
int rw = int_min(w, strlen(dlg_data->dlg->title));
int rw;
int y = 0;
int n = dlg_data->number_of_widgets - 2;
dlg_format_group(NULL, dlg_data->widgets_data, n,
0, &y, w, &rw);
#ifdef CONFIG_UTF_8
if (term->utf8)
rw = int_min(w, utf8_ptr2cells(dlg_data->dlg->title, NULL));
else
#endif /* CONFIG_UTF_8 */
rw = int_min(w, strlen(dlg_data->dlg->title));
dlg_format_group(term, dlg_data->widgets_data, n,
0, &y, w, &rw, 1);
y++;
dlg_format_buttons(NULL, dlg_data->widgets_data + n, 2, 0, &y, w,
&rw, ALIGN_CENTER);
dlg_format_buttons(term, dlg_data->widgets_data + n, 2, 0, &y, w,
&rw, ALIGN_CENTER, 1);
w = rw;
@ -110,9 +168,9 @@ group_layouter(struct dialog_data *dlg_data)
y = dlg_data->box.y + DIALOG_TB + 1;
dlg_format_group(term, dlg_data->widgets_data, n,
dlg_data->box.x + DIALOG_LB, &y, w, NULL);
dlg_data->box.x + DIALOG_LB, &y, w, NULL, 0);
y++;
dlg_format_buttons(term, dlg_data->widgets_data + n, 2,
dlg_data->box.x + DIALOG_LB, &y, w, &rw, ALIGN_CENTER);
dlg_data->box.x + DIALOG_LB, &y, w, &rw, ALIGN_CENTER, 0);
}

View File

@ -7,7 +7,7 @@ struct widget_data;
void dlg_format_group(struct terminal *term,
struct widget_data *widget_data,
int n, int x, int *y, int w, int *rw);
int n, int x, int *y, int w, int *rw, int format_only);
void group_layouter(struct dialog_data *);

View File

@ -17,6 +17,7 @@
#include "bfu/msgbox.h"
#include "bfu/text.h"
#include "config/kbdbind.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h"
#include "osdep/osdep.h"
#include "session/session.h"
@ -104,7 +105,7 @@ check_nonempty(struct dialog_data *dlg_data, struct widget_data *widget_data)
void
dlg_format_field(struct terminal *term,
struct widget_data *widget_data,
int x, int *y, int w, int *rw, enum format_align align)
int x, int *y, int w, int *rw, enum format_align align, int format_only)
{
static int max_label_width;
static int *prev_y; /* Assert the uniqueness of y */ /* TODO: get rid of this !! --Zas */
@ -129,9 +130,9 @@ dlg_format_field(struct terminal *term,
}
if (label && *label) {
if (term) text_color = get_bfu_color(term, "dialog.text");
if (!format_only) text_color = get_bfu_color(term, "dialog.text");
dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT);
dlg_format_text_do(term, label, x, y, w, rw, text_color, ALIGN_LEFT, format_only);
}
/* XXX: We want the field and label on the same line if the terminal
@ -141,7 +142,7 @@ dlg_format_field(struct terminal *term,
(*y) -= INPUTFIELD_HEIGHT;
dlg_format_text_do(term, INPUTFIELD_FLOAT_SEPARATOR,
x + label_width, y, w, rw,
text_color, ALIGN_LEFT);
text_color, ALIGN_LEFT, format_only);
w -= INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
x += INPUTFIELD_FLOAT_SEPARATOR_LEN + INPUTFIELD_FLOATLABEL_PADDING;
}
@ -265,11 +266,27 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
struct terminal *term = dlg_data->win->term;
struct color_pair *color;
int sel = is_selected_widget(dlg_data, widget_data);
#ifdef CONFIG_UTF_8
int len = 0, left = 0;
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
if (term->utf8) {
unsigned char *t = widget_data->cdata;
int p = widget_data->info.field.cpos;
len = utf8_ptr2cells(t, &t[p]);
int_bounds(&left, len - widget_data->box.width + 1, len);
int_lower_bound(&left, 0);
widget_data->info.field.vpos = utf8_cells2bytes(t, left, NULL);
} else
#endif /* CONFIG_UTF_8 */
{
int_bounds(&widget_data->info.field.vpos,
widget_data->info.field.cpos - widget_data->box.width + 1,
widget_data->info.field.cpos);
int_lower_bound(&widget_data->info.field.vpos, 0);
}
color = get_bfu_color(term, "dialog.field");
if (color)
@ -277,13 +294,26 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
color = get_bfu_color(term, "dialog.field-text");
if (color) {
int len = strlen(widget_data->cdata + widget_data->info.field.vpos);
int w = int_min(len, widget_data->box.width);
unsigned char *text = widget_data->cdata + widget_data->info.field.vpos;
int len, w;
#ifdef CONFIG_UTF_8
if (term->utf8 && !hide)
len = utf8_ptr2cells(text, NULL);
else if (term->utf8)
len = utf8_ptr2chars(text, NULL);
else
#endif /* CONFIG_UTF_8 */
len = strlen(text);
w = int_min(len, widget_data->box.width);
if (!hide) {
#ifdef CONFIG_UTF_8
if (term->utf8)
w = utf8_cells2bytes(text, w, NULL);
#endif /* CONFIG_UTF_8 */
draw_text(term, widget_data->box.x, widget_data->box.y,
widget_data->cdata + widget_data->info.field.vpos, w,
0, color);
text, w, 0, color);
} else {
struct box box;
@ -295,7 +325,14 @@ display_field_do(struct dialog_data *dlg_data, struct widget_data *widget_data,
}
if (sel) {
int x = widget_data->box.x + widget_data->info.field.cpos - widget_data->info.field.vpos;
int x;
#ifdef CONFIG_UTF_8
if (term->utf8)
x = widget_data->box.x + len - left;
else
#endif /* CONFIG_UTF_8 */
x = widget_data->box.x + widget_data->info.field.cpos - widget_data->info.field.vpos;
set_cursor(term, x, widget_data->box.y, 0);
set_window_ptr(dlg_data->win, widget_data->box.x, widget_data->box.y);
@ -435,13 +472,39 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
break;
case ACT_EDIT_RIGHT:
if (widget_data->info.field.cpos < strlen(widget_data->cdata))
if (widget_data->info.field.cpos < strlen(widget_data->cdata)) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
unsigned char *next = widget_data->cdata + widget_data->info.field.cpos;
unsigned char *end = strchr(next, '\0');
utf_8_to_unicode(&next, end);
widget_data->info.field.cpos = (int)(next - widget_data->cdata);
} else
#endif /* CONFIG_UTF_8 */
{
widget_data->info.field.cpos++;
}
}
goto display_field;
case ACT_EDIT_LEFT:
if (widget_data->info.field.cpos > 0)
widget_data->info.field.cpos--;
#ifdef CONFIG_UTF_8
if (widget_data->info.field.cpos && term->utf8) {
unsigned char *t = widget_data->cdata;
unsigned char *t2 = t;
int p = widget_data->info.field.cpos;
unsigned char tmp = t[p];
t[p] = '\0';
strlen_utf8(&t2);
t[p] = tmp;
widget_data->info.field.cpos = (int)(t2 - t);
}
#endif /* CONFIG_UTF_8 */
goto display_field;
case ACT_EDIT_HOME:
@ -453,6 +516,34 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
goto display_field;
case ACT_EDIT_BACKSPACE:
#ifdef CONFIG_UTF_8
if (widget_data->info.field.cpos && term->utf8) {
/* XXX: stolen from src/viewer/text/form.c */
/* FIXME: This isn't nice. We remove last byte
* from UTF-8 character to detect
* character before it. */
unsigned char *text = widget_data->cdata;
unsigned char *end = widget_data->cdata + widget_data->info.field.cpos - 1;
unicode_val_T data;
int old = widget_data->info.field.cpos;
while(1) {
data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR)
break;
}
widget_data->info.field.cpos = (int)(text - widget_data->cdata);
if (old != widget_data->info.field.cpos) {
int length;
text = widget_data->cdata;
length = strlen(text + old) + 1;
memmove(text + widget_data->info.field.cpos, text + old, length);
}
goto display_field;
}
#endif /* CONFIG_UTF_8 */
if (widget_data->info.field.cpos) {
memmove(widget_data->cdata + widget_data->info.field.cpos - 1,
widget_data->cdata + widget_data->info.field.cpos,
@ -467,6 +558,20 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
if (widget_data->info.field.cpos >= cdata_len) goto display_field;
#ifdef CONFIG_UTF_8
if (term->utf8) {
unsigned char *end = widget_data->cdata + cdata_len;
unsigned char *text = widget_data->cdata + widget_data->info.field.cpos;
unsigned char *old = text;
utf_8_to_unicode(&text, end);
if (old != text) {
memmove(old, text,
(int)(end - text) + 1);
}
goto display_field;
}
#endif /* CONFIG_UTF_8 */
memmove(widget_data->cdata + widget_data->info.field.cpos,
widget_data->cdata + widget_data->info.field.cpos + 1,
cdata_len - widget_data->info.field.cpos + 1);
@ -585,7 +690,22 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data)
memmove(text + 1, text, textlen + 1);
*text = get_kbd_key(ev);
#ifdef CONFIG_UTF_8
if (term->utf8) {
static unsigned char buf[7];
unsigned char *t = buf;
static int i = 0;
unicode_val_T data;
buf[i++] = *text;
buf[i] = '\0';
data = utf_8_to_unicode(&t, buf + i);
if (i == 6) i = 0;
if (data == UCS_NO_CHAR)
return EVENT_PROCESSED;
else i = 0;
}
#endif /* CONFIG_UTF_8 */
goto display_field;
}
}
@ -641,7 +761,7 @@ input_line_layouter(struct dialog_data *dlg_data)
- ses->status.show_tabs_bar;
dlg_format_field(win->term, dlg_data->widgets_data, 0,
&y, win->term->width, NULL, ALIGN_LEFT);
&y, win->term->width, NULL, ALIGN_LEFT, 0);
}
static widget_handler_status_T

View File

@ -62,7 +62,7 @@ extern struct widget_ops field_pass_ops;
widget_handler_status_T check_number(struct dialog_data *, struct widget_data *);
widget_handler_status_T check_nonempty(struct dialog_data *, struct widget_data *);
void dlg_format_field(struct terminal *, struct widget_data *, int, int *, int, int *, enum format_align);
void dlg_format_field(struct terminal *, struct widget_data *, int, int *, int, int *, enum format_align, int format_only);
void input_field(struct terminal *, struct memory_list *, int, unsigned char *,
unsigned char *, unsigned char *, unsigned char *, void *,

View File

@ -43,7 +43,7 @@ get_listbox_widget_data(struct widget_data *widget_data)
void
dlg_format_listbox(struct terminal *term, struct widget_data *widget_data,
int x, int *y, int w, int max_height, int *rw,
enum format_align align)
enum format_align align, int format_only)
{
int min, optimal_h, height;
@ -453,6 +453,7 @@ display_listbox_item(struct listbox_item *item, void *data_, int *offset)
} else {
unsigned char *text;
struct listbox_ops *ops = data->box->ops;
int len_bytes;
assert(ops && ops->get_info);
@ -461,8 +462,14 @@ display_listbox_item(struct listbox_item *item, void *data_, int *offset)
len = strlen(text);
int_upper_bound(&len, int_max(0, data->widget_data->box.width - depth * 5));
#ifdef CONFIG_UTF_8
if (data->term->utf8)
len_bytes = utf8_cells2bytes(text, len, NULL);
else
#endif /* CONFIG_UTF_8 */
len_bytes = len;
draw_text(data->term, x, y, text, len, 0, text_color);
draw_text(data->term, x, y, text, len_bytes, 0, text_color);
mem_free(text);
}

View File

@ -133,7 +133,7 @@ struct listbox_item {
extern struct widget_ops listbox_ops;
void dlg_format_listbox(struct terminal *, struct widget_data *, int, int *, int, int, int *, enum format_align);
void dlg_format_listbox(struct terminal *, struct widget_data *, int, int *, int, int, int *, enum format_align, int format_only);
struct listbox_item *traverse_listbox_items_list(struct listbox_item *, struct listbox_data *, int, int, int (*)(struct listbox_item *, void *, int *), void *);

View File

@ -200,7 +200,14 @@ get_menuitem_text_width(struct terminal *term, struct menu_item *mi)
if (!text[0]) return 0;
return L_TEXT_SPACE + strlen(text) - !!mi->hotkey_pos + R_TEXT_SPACE;
#ifdef CONFIG_UTF_8
if (term->utf8)
return L_TEXT_SPACE + utf8_ptr2cells(text, NULL)
- !!mi->hotkey_pos + R_TEXT_SPACE;
else
#endif /* CONFIG_UTF_8 */
return L_TEXT_SPACE + strlen(text)
- !!mi->hotkey_pos + R_TEXT_SPACE;
}
/* Get desired width for right text in menu item, accounting spacing. */
@ -360,17 +367,31 @@ set_menu_selection(struct menu *menu, int pos)
int_bounds(&menu->first, 0, menu->size - height);
}
/* width - number of standard terminal cells to be displayed (text + whitespace
* separators). For double-width glyph width == 2.
* len - length of text in bytes */
static inline void
draw_menu_left_text(struct terminal *term, unsigned char *text, int len,
int x, int y, int width, struct color_pair *color)
{
int w = width - (L_TEXT_SPACE + R_TEXT_SPACE);
int max_len;
if (w <= 0) return;
if (len < 0) len = strlen(text);
if (!len) return;
if (len > w) len = w;
#ifdef CONFIG_UTF_8
if (term->utf8) {
max_len = utf8_cells2bytes(text, w, NULL);
if (max_len <= 0)
return;
} else
#endif /* CONFIG_UTF_8 */
max_len = w;
if (len > max_len) len = max_len;
draw_text(term, x + L_TEXT_SPACE, y, text, len, 0, color);
}
@ -389,6 +410,10 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
int xbase = x + L_TEXT_SPACE;
int w = width - (L_TEXT_SPACE + R_TEXT_SPACE);
int hk_state = 0;
#ifdef CONFIG_UTF_8
unsigned char *text2, *end;
#endif
#ifdef CONFIG_DEBUG
/* For redundant hotkeys highlighting. */
int double_hk = 0;
@ -405,6 +430,10 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
hk_color_sel = tmp;
}
#ifdef CONFIG_UTF_8
if (term->utf8) goto utf8;
#endif /* CONFIG_UTF_8 */
for (x = 0; x - !!hk_state < w && (c = text[x]); x++) {
if (!hk_state && x == hotkey_pos - 1) {
hk_state = 1;
@ -417,12 +446,78 @@ draw_menu_left_text_hk(struct terminal *term, unsigned char *text,
(double_hk ? hk_color_sel : hk_color));
#else
draw_char(term, xbase + x - 1, y, c, hk_attr, hk_color);
#endif
#endif /* CONFIG_DEBUG */
hk_state = 2;
} else {
draw_char(term, xbase + x - !!hk_state, y, c, 0, color);
}
}
return;
#ifdef CONFIG_UTF_8
utf8:
end = strchr(text, '\0');
text2 = text;
for (x = 0; x - !!hk_state < w && *text2; x++) {
unicode_val_T data;
data = utf_8_to_unicode(&text2, end);
if (!hk_state && (int)(text2 - text) == hotkey_pos) {
hk_state = 1;
continue;
}
if (hk_state == 1) {
if (unicode_to_cell(data) == 2) {
if (x < w && xbase + x < term->width) {
#ifdef CONFIG_DEBUG
draw_char(term, xbase + x - 1, y,
data, hk_attr,
(double_hk ? hk_color_sel
: hk_color));
#else
draw_char(term, xbase + x - 1, y,
data, hk_attr, hk_color);
#endif /* CONFIG_DEBUG */
x++;
draw_char(term, xbase + x - 1, y,
UCS_NO_CHAR, 0, hk_color);
} else {
draw_char(term, xbase + x - 1, y,
' ', 0, hk_color);
}
} else {
#ifdef CONFIG_DEBUG
draw_char(term, xbase + x - 1, y,
data, hk_attr,
(double_hk ? hk_color_sel
: hk_color));
#else
draw_char(term, xbase + x - 1, y,
data, hk_attr, hk_color);
#endif /* CONFIG_DEBUG */
}
hk_state = 2;
} else {
if (unicode_to_cell(data) == 2) {
if (x - !!hk_state + 1 < w &&
xbase + x - !!hk_state + 1 < term->width) {
draw_char(term, xbase + x - !!hk_state,
y, data, 0, color);
x++;
draw_char(term, xbase + x - !!hk_state,
y, UCS_NO_CHAR, 0, color);
} else {
draw_char(term, xbase + x - !!hk_state,
y, ' ', 0, color);
}
} else {
draw_char(term, xbase + x - !!hk_state,
y, data, 0, color);
}
}
}
#endif /* CONFIG_UTF_8 */
}
static inline void
@ -465,7 +560,15 @@ display_menu(struct terminal *term, struct menu *menu)
/* Draw shadow */
draw_shadow(term, &menu->box,
get_bfu_color(term, "dialog.shadow"), 2, 1);
#ifdef CONFIG_UTF_8
if (term->utf8)
fix_dwchar_around_box(term, &box, 1, 2, 1);
#endif /* CONFIG_UTF_8 */
}
#ifdef CONFIG_UTF_8
else if(term->utf8)
fix_dwchar_around_box(term, &box, 1, 0, 0);
#endif /* CONFIG_UTF_8 */
menu_height = box.height;
box.height = 1;
@ -1005,18 +1108,33 @@ display_mainmenu(struct terminal *term, struct menu *menu)
int l = mi->hotkey_pos;
int textlen;
int selected = (i == menu->selected);
int screencnt;
if (mi_text_translate(mi))
text = _(text, term);
textlen = strlen(text) - !!l;
#ifdef CONFIG_UTF_8
if (term->utf8)
screencnt = utf8_ptr2cells(text, NULL) - !!l;
else
#endif /* CONFIG_UTF_8 */
screencnt = textlen;
if (selected) {
color = selected_color;
box.x = p;
#ifdef CONFIG_UTF_8
if (term->utf8)
box.width = L_MAINTEXT_SPACE + L_TEXT_SPACE
+ screencnt
+ R_TEXT_SPACE + R_MAINTEXT_SPACE;
else
#endif /* CONFIG_UTF_8 */
box.width = L_MAINTEXT_SPACE + L_TEXT_SPACE
+ textlen
+ R_TEXT_SPACE + R_MAINTEXT_SPACE;
draw_box(term, &box, ' ', 0, color);
set_cursor(term, p, 0, 1);
set_window_ptr(menu->win, p, 1);
@ -1034,7 +1152,7 @@ display_mainmenu(struct terminal *term, struct menu *menu)
color);
}
p += textlen;
p += screencnt;
if (p >= term->width - R_MAINMENU_SPACE)
break;
@ -1045,6 +1163,22 @@ display_mainmenu(struct terminal *term, struct menu *menu)
menu->last = i - 1;
int_lower_bound(&menu->last, menu->first);
if (menu->last < menu->size - 1) {
#ifdef CONFIG_UTF_8
if (term->utf8) {
struct screen_char *schar;
schar = get_char(term, term->width - R_MAINMENU_SPACE, 0);
/* Is second cell of double-width char on the place where
* first char of the R_MAINMENU_SPACE will be displayed? */
if (schar->data == UCS_NO_CHAR) {
/* Replace double-width char with ' '. */
schar++;
draw_char_data(term, term->width - R_MAINMENU_SPACE - 1,
0, ' ');
}
}
#endif
set_box(&box,
term->width - R_MAINMENU_SPACE, 0,
R_MAINMENU_SPACE, 1);

View File

@ -19,6 +19,7 @@
#include "terminal/terminal.h"
#include "util/color.h"
/* FIXME: For UTF-8 strings we need better function than isspace. */
#define is_unsplitable(pos) (*(pos) && *(pos) != '\n' && !isspace(*(pos)))
void
@ -35,48 +36,107 @@ add_dlg_text(struct dialog *dlg, unsigned char *text,
}
/* Returns length of substring (from start of @text) before a split. */
#ifdef CONFIG_UTF_8
static inline int
split_line(unsigned char *text, int max_width)
split_line(unsigned char *text, int max_width, int *cells, int utf8)
#else
static inline int
split_line(unsigned char *text, int max_width, int *cells)
#endif /* CONFIG_UTF_8 */
{
unsigned char *split = text;
int cells_save = *cells;
if (max_width <= 0) return 0;
while (*split && *split != '\n') {
unsigned char *next_split = split + 1;
unsigned char *next_split;
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *next_char_begin = split
+ utf8charlen(split);
next_split = split;
*cells += utf8_char2cells(split, NULL);
while (*next_split && next_split != next_char_begin)
next_split++;
next_char_begin = next_split;
while (is_unsplitable(next_split))
{
if (next_split < next_char_begin) {
next_split++;
continue;
}
*cells += utf8_char2cells(next_split, NULL);
next_char_begin += utf8charlen(next_split);
}
} else
#endif /* CONFIG_UTF_8 */
{
next_split = split + 1;
while (is_unsplitable(next_split))
next_split++;
*cells = next_split - text;
}
if (next_split - text > max_width) {
if (*cells > max_width) {
/* Force a split if no position was found yet,
* meaning there's no splittable substring under
* requested width. */
if (split == text) {
#ifdef CONFIG_UTF_8
if (utf8) {
int m_bytes = utf8_cells2bytes(text,
max_width,
NULL);
split = &text[m_bytes];
} else
#endif /* CONFIG_UTF_8 */
split = &text[max_width];
/* Give preference to split on a punctuation
* if any. Note that most of the time
* punctuation char is followed by a space so
* this rule will not match often.
* We match dash and quotes too. */
/* FIXME: Function ispunct won't work correctly
* with UTF-8 characters. We need some similar
* function for UTF-8 characters. */
#ifdef CONFIG_UTF_8
if (!utf8)
#endif /* CONFIG_UTF_8 */
{
/* Give preference to split on a
* punctuation if any. Note that most
* of the time punctuation char is
* followed by a space so this rule
* will not match often. We match dash
* and quotes too. */
cells_save--;
while (--split != text) {
cells_save--;
if (!ispunct(*split)) continue;
split++;
cells_save++;
break;
}
}
/* If no way to do a clean split, just return
* requested maximal width. */
if (split == text)
if (split == text) {
*cells = max_width;
return max_width;
}
}
break;
}
cells_save = *cells;
split = next_split;
}
*cells = cells_save;
return split - text;
}
@ -86,8 +146,13 @@ split_line(unsigned char *text, int max_width)
#define realloc_lines(x, o, n) mem_align_alloc(x, o, n, LINES_GRANULARITY)
/* Find the start of each line with the current max width */
#ifdef CONFIG_UTF_8
static unsigned char **
split_lines(struct widget_data *widget_data, int max_width, int utf8)
#else
static unsigned char **
split_lines(struct widget_data *widget_data, int max_width)
#endif /* CONFIG_UTF_8 */
{
unsigned char *text = widget_data->widget->text;
unsigned char **lines = (unsigned char **) widget_data->cdata;
@ -100,19 +165,27 @@ split_lines(struct widget_data *widget_data, int max_width)
while (*text) {
int width;
int cells = 0;
/* Skip first leading \n or space. */
if (isspace(*text)) text++;
if (!*text) break;
width = split_line(text, max_width);
#ifdef CONFIG_UTF_8
width = split_line(text, max_width, &cells, utf8);
#else
width = split_line(text, max_width, &cells);
#endif
/* split_line() may return 0. */
if (width < 1) {
width = 1; /* Infinite loop prevention. */
}
if (cells < 1) {
cells = 1; /* Infinite loop prevention. */
}
int_lower_bound(&widget_data->box.width, width);
int_lower_bound(&widget_data->box.width, cells);
if (!realloc_lines(&lines, line, line + 1))
break;
@ -134,13 +207,15 @@ split_lines(struct widget_data *widget_data, int max_width)
void
dlg_format_text_do(struct terminal *term, unsigned char *text,
int x, int *y, int width, int *real_width,
struct color_pair *color, enum format_align align)
struct color_pair *color, enum format_align align,
int format_only)
{
int line_width;
int firstline = 1;
for (; *text; text += line_width, (*y)++) {
int shift;
int cells = 0;
/* Skip first leading \n or space. */
if (!firstline && isspace(*text))
@ -149,7 +224,11 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
firstline = 0;
if (!*text) break;
line_width = split_line(text, width);
#ifdef CONFIG_UTF_8
line_width = split_line(text, width, &cells, term->utf8);
#else
line_width = split_line(text, width, &cells);
#endif /* CONFIG_UTF_8 */
/* split_line() may return 0. */
if (line_width < 1) {
@ -157,18 +236,18 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
continue;
}
if (real_width) int_lower_bound(real_width, line_width);
if (!term || !line_width) continue;
if (real_width) int_lower_bound(real_width, cells);
if (format_only || !line_width) continue;
/* Calculate the number of chars to indent */
if (align == ALIGN_CENTER)
shift = (width - line_width) / 2;
shift = (width - cells) / 2;
else if (align == ALIGN_RIGHT)
shift = width - line_width;
shift = width - cells;
else
shift = 0;
assert(line_width <= width && shift < width);
assert(cells <= width && shift < width);
draw_text(term, x + shift, *y, text, line_width, 0, color);
}
@ -176,7 +255,8 @@ dlg_format_text_do(struct terminal *term, unsigned char *text,
void
dlg_format_text(struct terminal *term, struct widget_data *widget_data,
int x, int *y, int width, int *real_width, int max_height)
int x, int *y, int width, int *real_width, int max_height,
int format_only)
{
unsigned char *text = widget_data->widget->text;
unsigned char saved = 0;
@ -202,9 +282,15 @@ dlg_format_text(struct terminal *term, struct widget_data *widget_data,
/* Ensure that the current split is valid but don't
* split if we don't have to */
#ifdef CONFIG_UTF_8
if (widget_data->box.width != width
&& !split_lines(widget_data, width, term->utf8))
return;
#else
if (widget_data->box.width != width
&& !split_lines(widget_data, width))
return;
#endif
lines = (unsigned char **) widget_data->cdata;
@ -246,7 +332,7 @@ dlg_format_text(struct terminal *term, struct widget_data *widget_data,
dlg_format_text_do(term, text,
x, y, width, real_width,
get_bfu_color(term, "dialog.text"),
widget_data->widget->info.text.align);
widget_data->widget->info.text.align, format_only);
if (widget_data->widget->info.text.is_label) (*y)--;
@ -333,7 +419,7 @@ format_and_display_text(struct widget_data *widget_data,
dlg_format_text(term, widget_data,
widget_data->box.x, &y, widget_data->box.width, NULL,
height);
height, 0);
display_text(dlg_data, widget_data);
redraw_from_window(dlg_data->win);

View File

@ -47,11 +47,11 @@ void add_dlg_text(struct dialog *dlg, unsigned char *text,
extern struct widget_ops text_ops;
void dlg_format_text_do(struct terminal *term,
unsigned char *text, int x, int *y, int w, int *rw,
struct color_pair *scolor, enum format_align align);
struct color_pair *scolor, enum format_align align, int format_only);
void
dlg_format_text(struct terminal *term, struct widget_data *widget_data,
int x, int *y, int dlg_width, int *real_width, int height);
int x, int *y, int dlg_width, int *real_width, int height, int format_only);
#define text_is_scrollable(widget_data) \
((widget_data)->widget->info.text.is_scrollable \

View File

@ -145,6 +145,11 @@ download_dialog_layouter(struct dialog_data *dlg_data)
mem_free(msg);
return;
}
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri(url);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(url);
url_len = strlen(url);
@ -152,8 +157,8 @@ download_dialog_layouter(struct dialog_data *dlg_data)
int_lower_bound(&w, DOWN_DLG_MIN);
}
dlg_format_text_do(NULL, url, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT);
dlg_format_text_do(term, url, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT, 1);
y++;
if (show_meter) y += 2;
@ -161,13 +166,13 @@ download_dialog_layouter(struct dialog_data *dlg_data)
#if CONFIG_BITTORRENT
if (bittorrent) y += 2;
#endif
dlg_format_text_do(NULL, msg, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT);
dlg_format_text_do(term, msg, 0, &y, w, &rw,
dialog_text_color, ALIGN_LEFT, 1);
y++;
dlg_format_buttons(NULL, dlg_data->widgets_data,
dlg_format_buttons(term, dlg_data->widgets_data,
dlg_data->number_of_widgets, 0, &y, w,
&rw, ALIGN_CENTER);
&rw, ALIGN_CENTER, 1);
draw_dialog(dlg_data, w, y);
@ -186,7 +191,7 @@ download_dialog_layouter(struct dialog_data *dlg_data)
y = dlg_data->box.y + DIALOG_TB + 1;
x = dlg_data->box.x + DIALOG_LB;
dlg_format_text_do(term, url, x, &y, w, NULL,
dialog_text_color, ALIGN_LEFT);
dialog_text_color, ALIGN_LEFT, 0);
if (show_meter) {
y++;
@ -203,12 +208,12 @@ download_dialog_layouter(struct dialog_data *dlg_data)
#endif
y++;
dlg_format_text_do(term, msg, x, &y, w, NULL,
dialog_text_color, ALIGN_LEFT);
dialog_text_color, ALIGN_LEFT, 0);
y++;
dlg_format_buttons(term, dlg_data->widgets_data,
dlg_data->number_of_widgets, x, &y, w,
NULL, ALIGN_CENTER);
NULL, ALIGN_CENTER, 0);
mem_free(url);
mem_free(msg);
@ -296,7 +301,14 @@ get_file_download_text(struct listbox_item *item, struct terminal *term)
unsigned char *uristring;
uristring = get_uri_string(file_download->uri, URI_PUBLIC);
if (uristring) decode_uri_for_display(uristring);
if (uristring) {
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri(uristring);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(uristring);
}
return uristring;
}
@ -369,7 +381,7 @@ draw_file_download(struct listbox_item *item, struct listbox_context *context,
color = get_bfu_color(context->term, stylename);
text = get_file_download_text(item, NULL);
text = get_file_download_text(item, context->term);
if (!text) return;
length = strlen(text);

View File

@ -581,6 +581,11 @@ query_file(struct session *ses, struct uri *uri, void *data,
add_mime_filename_to_string(&def, uri);
/* Remove the %-ugliness for display */
#ifdef CONFIG_UTF_8
if (ses->tab->term->utf8)
decode_uri_string(&def);
else
#endif /* CONFIG_UTF_8 */
decode_uri_string_for_display(&def);
if (interactive) {

View File

@ -59,8 +59,10 @@ charset_list(struct terminal *term, void *xxx, void *ses_)
unsigned char *name = get_cp_name(i);
if (!name) break;
if (is_cp_special(i))
continue;
#ifndef CONFIG_UTF_8
if (is_cp_utf8(i)) continue;
#endif /* CONFIG_UTF_8 */
items++;
add_to_menu(&mi, name, NULL, ACT_MAIN_NONE,

View File

@ -150,15 +150,8 @@ get_current_link_info_and_title(struct session *ses,
link_title = get_current_link_title(doc_view);
if (link_title) {
unsigned char *src;
assert(*link_title);
/* Remove illicit chars. */
for (src = link_title; *src; src++)
if (!isprint(*src) || iscntrl(*src))
*src = '*';
ret = straconcat(link_info, " - ", link_title, NULL);
mem_free(link_info);
mem_free(link_title);
@ -424,11 +417,25 @@ display_title_bar(struct session *ses, struct terminal *term)
if (document->title) {
int maxlen = int_max(term->width - 4 - buflen, 0);
int titlelen = int_min(strlen(document->title), maxlen);
int titlelen, titlewidth;
#ifdef CONFIG_UTF_8
if (term->utf8) {
titlewidth = utf8_ptr2cells(document->title, NULL);
titlewidth = int_min(titlewidth, maxlen);
titlelen = utf8_cells2bytes(document->title,
titlewidth, NULL);
} else
#endif /* CONFIG_UTF_8 */
{
titlewidth = int_min(strlen(document->title), maxlen);
titlelen = titlewidth;
}
add_bytes_to_string(&title, document->title, titlelen);
if (titlelen == maxlen)
if (titlewidth == maxlen)
add_bytes_to_string(&title, "...", 3);
}
@ -436,7 +443,16 @@ display_title_bar(struct session *ses, struct terminal *term)
add_bytes_to_string(&title, buf, buflen);
if (title.length) {
int x = int_max(term->width - 1 - title.length, 0);
int x;
#ifdef CONFIG_UTF_8
if (term->utf8) {
x = int_max(term->width - 1
- utf8_ptr2cells(title.source,
title.source
+ title.length), 0);
} else
#endif /* CONFIG_UTF_8 */
x = int_max(term->width - 1 - title.length, 0);
draw_text(term, x, 0, title.source, title.length, 0,
get_bfu_color(term, "title.title-text"));

View File

@ -119,8 +119,7 @@ static css_applier_T css_appliers[CSS_PT_LAST] = {
static void
examine_element(struct html_context *html_context, struct css_selector *base,
enum css_selector_type seltype, enum css_selector_relation rel,
struct list_head *selectors, struct html_element *element,
struct list_head *html_stack)
struct list_head *selectors, struct html_element *element)
{
struct css_selector *selector;
unsigned char *code;
@ -138,7 +137,8 @@ examine_element(struct html_context *html_context, struct css_selector *base,
dbginfo(sel, type, base); \
merge_css_selectors(base, sel); \
/* Ancestor matches? */ \
if ((struct list_head *) element->next != html_stack) { \
if ((struct list_head *) element->next \
!= &html_context->stack) { \
struct html_element *ancestor; \
/* This is less effective than doing reverse iterations,
* first over sel->leaves and then over the HTML stack,
@ -147,21 +147,20 @@ examine_element(struct html_context *html_context, struct css_selector *base,
* have to duplicate the whole examine_element(), so if
* profiles won't show it really costs... */ \
for (ancestor = element->next; \
(struct list_head *) ancestor != html_stack;\
(struct list_head *) ancestor \
!= &html_context->stack;\
ancestor = ancestor->next) \
examine_element(html_context, base, \
CST_ELEMENT, CSR_ANCESTOR, \
&sel->leaves, ancestor, \
html_stack); \
&sel->leaves, ancestor); \
examine_element(html_context, base, \
CST_ELEMENT, CSR_PARENT, \
&sel->leaves, element->next, \
html_stack); \
&sel->leaves, element->next); \
} \
/* More specific matches? */ \
examine_element(html_context, base, type + 1, \
CSR_SPECIFITY, \
&sel->leaves, element, html_stack); \
&sel->leaves, element); \
}
if (seltype <= CST_ELEMENT && element->namelen) {
@ -235,7 +234,7 @@ get_css_selector_for_element(struct html_context *html_context,
#endif
examine_element(html_context, selector, CST_ELEMENT, CSR_ROOT,
&css->selectors, element, html_stack);
&css->selectors, element);
#ifdef DEBUG_CSS
DBG("Element %.*s applied.", element->namelen, element->name);

View File

@ -118,13 +118,19 @@ struct link {
#define get_link_name(link) \
(!link_is_form(link) ? (link)->data.name : NULL)
#ifdef CONFIG_UTF_8
struct search {
int x, y;
signed int n; /* RAM is cheap nowadays */
unicode_val_T c;
};
#else
struct search {
int x, y;
signed int n:24; /* This structure is size-critical */
unsigned char c;
};
#endif
struct document {
OBJECT_HEAD(struct document);
@ -176,6 +182,10 @@ struct document {
struct search **slines1;
struct search **slines2;
#ifdef CONFIG_UTF_8
unsigned char buf[7];
unsigned char buf_length;
#endif
unsigned int id; /* Used to check cache entries. */
int cp;

View File

@ -260,7 +260,12 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
struct document *document = renderer->document;
struct conv_table *convert = renderer->convert_table;
enum convert_string_mode mode = renderer->convert_mode;
int x;
int x, charlen;
#ifdef CONFIG_UTF_8
int utf8 = document->options.utf8;
unsigned char *end;
#endif /* CONFIG_UTF_8 */
assert(renderer && template && string && length);
@ -275,12 +280,15 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
add_search_node(renderer, length);
for (x = 0; x < length; x++, renderer->canvas_x++) {
unsigned char data = string[x];
#ifdef CONFIG_UTF_8
end = string + length;
#endif /* CONFIG_UTF_8 */
for (x = 0, charlen = 1; x < length;x += charlen, renderer->canvas_x++) {
unsigned char *text = &string[x];
/* This is mostly to be able to break out so the indentation
* level won't get to high. */
switch (data) {
switch (*text) {
case ASCII_TAB:
{
int tab_width = 7 - (X(renderer) & 7);
@ -295,15 +303,33 @@ render_dom_line(struct dom_renderer *renderer, struct screen_char *template,
* ``main loop'' add the actual tab char. */
for (; tab_width-- > 0; renderer->canvas_x++)
copy_screen_chars(POS(renderer), template, 1);
charlen = 1;
break;
}
default:
template->data = isscreensafe(data) ? data : '.';
#ifdef CONFIG_UTF_8
if (utf8) {
unicode_val_T data;
charlen = utf8charlen(text);
data = utf_8_to_unicode(&text, end);
template->data = (unicode_val_T)data;
if (unicode_to_cell(data) == 2) {
copy_screen_chars(POS(renderer),
template, 1);
X(renderer)++;
template->data = UCS_NO_CHAR;
}
} else
#endif /* CONFIG_UTF_8 */
template->data = isscreensafe(*text) ? *text:'.';
}
copy_screen_chars(POS(renderer), template, 1);
}
mem_free(string);
}
@ -1024,6 +1050,9 @@ render_dom_document(struct cache_entry *cached, struct document *document,
init_dom_renderer(&renderer, document, buffer, convert_table);
document->bgcolor = document->options.default_bg;
#ifdef CONFIG_UTF_8
document->options.utf8 = is_cp_utf8(document->options.cp);
#endif /* CONFIG_UTF_8 */
if (document->options.plain)
parser_type = SGML_PARSER_STREAM;

View File

@ -495,6 +495,12 @@ end_parse:
max_width = 0;
for (i = 0; i < order; i++) {
if (!labels[i]) continue;
#ifdef CONFIG_UTF_8
if (html_context->options->utf8)
int_lower_bound(&max_width,
utf8_ptr2cells(labels[i], NULL));
else
#endif /* CONFIG_UTF_8 */
int_lower_bound(&max_width, strlen(labels[i]));
}

View File

@ -23,6 +23,7 @@
#include "document/refresh.h"
#include "document/renderer.h"
#include "intl/charsets.h"
#include "osdep/types.h"
#include "protocol/uri.h"
#include "session/session.h"
#include "terminal/color.h"
@ -209,6 +210,10 @@ realloc_spaces(struct part *part, int length)
if (!ALIGN_SPACES(&part->spaces, part->spaces_len, length))
return -1;
#ifdef CONFIG_UTF_8
if (!ALIGN_SPACES(&part->char_width, part->spaces_len, length))
return -1;
#endif
part->spaces_len = length;
@ -374,6 +379,155 @@ get_format_screen_char(struct html_context *html_context,
return &schar_cache;
}
#ifdef CONFIG_UTF_8
/* First possibly do the format change and then find out what coordinates
* to use since sub- or superscript might change them */
static inline int
set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
enum link_state link_state)
{
struct part *part = html_context->part;
struct screen_char *schar = get_format_screen_char(html_context,
link_state);
int x = part->cx;
int y = part->cy;
int x2 = x;
int len = charslen;
int utf8 = html_context->options->utf8;
assert(part);
if_assert_failed return len;
assert(charslen >= 0);
if (realloc_spaces(part, x + charslen))
return 0;
if (part->document) {
if (realloc_line(html_context, part->document,
Y(y), X(x) + charslen - 1))
return 0;
if (utf8) {
unsigned char *end = chars + charslen;
unicode_val_T data;
if (part->document->buf_length) {
/* previous char was broken in the middle */
int length = utf8charlen(part->document->buf);
unsigned char i;
unsigned char *buf_ptr = part->document->buf;
for (i = part->document->buf_length; i < length && chars < end;) {
part->document->buf[i++] = *chars++;
}
part->document->buf_length = i;
part->document->buf[i] = '\0';
data = utf_8_to_unicode(&buf_ptr, buf_ptr + i);
if (data != UCS_NO_CHAR) {
part->document->buf_length = 0;
goto good_char;
} else {
/* Still not full char */
return 0;
}
}
for (; chars < end; x++) {
if (*chars == NBSP_CHAR) {
schar->data = ' ';
part->spaces[x] = html_context->options->wrap_nbsp;
part->char_width[x] = 1;
chars++;
} else {
part->spaces[x] = (*chars == ' ');
data = utf_8_to_unicode(&chars, end);
if (data == UCS_NO_CHAR) {
if (charslen == 1) {
/* HR */
unsigned char attr = schar->attr;
schar->data = *chars++;
schar->attr = SCREEN_ATTR_FRAME;
copy_screen_chars(&POS(x, y), schar, 1);
schar->attr = attr;
part->char_width[x] = 0;
continue;
} else {
unsigned char i;
broken_char: /* broken char */
for (i = 0; chars < end;i++) {
part->document->buf[i] = *chars++;
}
part->document->buf_length = i;
return x - x2;
}
} else {
good_char:
if (unicode_to_cell(data) == 2) {
schar->data = (unicode_val_T)data;
part->char_width[x] = 2;
copy_screen_chars(&POS(x++, y), schar, 1);
data = utf_8_to_unicode(&chars, end);
if (data == UCS_NO_CHAR) goto broken_char;
schar->data = (unicode_val_T)data;
part->spaces[x] = 0;
part->char_width[x] = 0;
} else {
part->char_width[x] = unicode_to_cell(data);
schar->data = (unicode_val_T)data;
}
}
}
copy_screen_chars(&POS(x, y), schar, 1);
}
} else {
for (; charslen > 0; charslen--, x++, chars++) {
part->char_width[x] = 1;
if (*chars == NBSP_CHAR) {
schar->data = ' ';
part->spaces[x] = html_context->options->wrap_nbsp;
} else {
part->spaces[x] = (*chars == ' ');
schar->data = *chars;
}
copy_screen_chars(&POS(x, y), schar, 1);
}
}
len = x - x2;
} else {
if (utf8) {
unsigned char *end;
for (end = chars + charslen; chars < end; x++) {
unicode_val_T data;
part->spaces[x] = (*chars == ' ');
data = utf_8_to_unicode(&chars, end);
part->char_width[x] = unicode_to_cell(data);
if (part->char_width[x] == 2) {
x++;
part->spaces[x] = 0;
part->char_width[x] = 0;
data = utf_8_to_unicode(&chars, end);
}
if (data == UCS_NO_CHAR) {
/* this is at the end only */
return x - x2;
}
}
len = x - x2;
} else {
for (; charslen > 0; charslen--, x++, chars++) {
part->spaces[x] = (*chars == ' ');
part->char_width[x] = 1;
}
}
}
return len;
}
#else
/* First possibly do the format change and then find out what coordinates
* to use since sub- or superscript might change them */
static inline void
@ -405,7 +559,6 @@ set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
part->spaces[x] = (*chars == ' ');
schar->data = *chars;
}
copy_screen_chars(&POS(x, y), schar, 1);
}
} else {
@ -414,6 +567,7 @@ set_hline(struct html_context *html_context, unsigned char *chars, int charslen,
}
}
}
#endif /* CONFIG_UTF_8 */
static void
move_links(struct html_context *html_context, int xf, int yf, int xt, int yt)
@ -645,29 +799,53 @@ split_line_at(struct html_context *html_context, int width)
if (part->document) {
assert(part->document->data);
if_assert_failed return 0;
#ifdef CONFIG_UTF_8
if (html_context->options->utf8
&& width < part->spaces_len && part->char_width[width] == 2) {
move_chars(html_context, width, part->cy, par_format.leftmargin, part->cy + 1);
del_chars(html_context, width, part->cy);
} else
#endif
{
assertm(POS(width, part->cy).data == ' ',
"bad split: %c", POS(width, part->cy).data);
move_chars(html_context, width + 1, part->cy, par_format.leftmargin, part->cy + 1);
del_chars(html_context, width, part->cy);
}
}
#ifdef CONFIG_UTF_8
if (!(html_context->options->utf8
&& width < part->spaces_len
&& part->char_width[width] == 2))
#endif
width++; /* Since we were using (x + 1) only later... */
tmp = part->spaces_len - width;
if (tmp > 0) {
/* 0 is possible and I'm paranoid ... --Zas */
memmove(part->spaces, part->spaces + width, tmp);
#ifdef CONFIG_UTF_8
memmove(part->char_width, part->char_width + width, tmp);
#endif
}
assert(tmp >= 0);
if_assert_failed tmp = 0;
memset(part->spaces + tmp, 0, width);
#ifdef CONFIG_UTF_8
memset(part->char_width + tmp, 0, width);
#endif
if (par_format.leftmargin > 0) {
tmp = part->spaces_len - par_format.leftmargin;
assertm(tmp > 0, "part->spaces_len - par_format.leftmargin == %d", tmp);
/* So tmp is zero, memmove() should survive that. Don't recover. */
memmove(part->spaces + par_format.leftmargin, part->spaces, tmp);
#ifdef CONFIG_UTF_8
memmove(part->char_width + par_format.leftmargin, part->char_width, tmp);
#endif
}
part->cy++;
@ -705,6 +883,30 @@ split_line(struct html_context *html_context)
assert(part);
if_assert_failed return 0;
#ifdef CONFIG_UTF_8
if (html_context->options->utf8) {
for (x = overlap(par_format); x >= par_format.leftmargin; x--) {
if (x < part->spaces_len && (part->spaces[x]
|| (part->char_width[x] == 2
/* Ugly hack. If we haven't place for
* double-width characters we print two
* double-width characters. */
&& x != par_format.leftmargin)))
return split_line_at(html_context, x);
}
for (x = par_format.leftmargin; x < part->cx ; x++) {
if (x < part->spaces_len && (part->spaces[x]
|| (part->char_width[x] == 2
/* We want to break line after _second_
* double-width character. */
&& x > par_format.leftmargin)))
return split_line_at(html_context, x);
}
} else
#endif
{
for (x = overlap(par_format); x >= par_format.leftmargin; x--)
if (x < part->spaces_len && part->spaces[x])
return split_line_at(html_context, x);
@ -712,6 +914,7 @@ split_line(struct html_context *html_context)
for (x = par_format.leftmargin; x < part->cx ; x++)
if (x < part->spaces_len && part->spaces[x])
return split_line_at(html_context, x);
}
/* Make sure that we count the right margin to the total
* actual box width. */
@ -1140,9 +1343,15 @@ done_link_state_info(void)
sizeof(renderer_context.link_state_info));
}
#ifdef CONFIG_UTF_8
static inline void
process_link(struct html_context *html_context, enum link_state link_state,
unsigned char *chars, int charslen, int cells)
#else
static inline void
process_link(struct html_context *html_context, enum link_state link_state,
unsigned char *chars, int charslen)
#endif /* CONFIG_UTF_8 */
{
struct part *part = html_context->part;
struct link *link;
@ -1194,6 +1403,9 @@ process_link(struct html_context *html_context, enum link_state link_state,
if (x_offset) {
charslen -= x_offset;
chars += x_offset;
#ifdef CONFIG_UTF_8
cells -= x_offset;
#endif /* CONFIG_UTF_8 */
}
link = new_link(html_context, chars, charslen);
@ -1208,14 +1420,26 @@ process_link(struct html_context *html_context, enum link_state link_state,
}
/* Add new canvas positions to the link. */
if (realloc_points(link, link->npoints + charslen)) {
#ifdef CONFIG_UTF_8
if (realloc_points(link, link->npoints + cells))
#else
if (realloc_points(link, link->npoints + charslen))
#endif /* CONFIG_UTF_8 */
{
struct point *point = &link->points[link->npoints];
int x = X(part->cx) + x_offset;
int y = Y(part->cy);
#ifdef CONFIG_UTF_8
link->npoints += cells;
for (; cells > 0; cells--, point++, x++)
#else
link->npoints += charslen;
for (; charslen > 0; charslen--, point++, x++) {
for (; charslen > 0; charslen--, point++, x++)
#endif /* CONFIG_UTF_8 */
{
point->x = x;
point->y = y;
}
@ -1266,6 +1490,9 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
{
enum link_state link_state;
struct part *part;
#ifdef CONFIG_UTF_8
int cells;
#endif /* CONFIG_UTF_8 */
assert(html_context);
if_assert_failed return;
@ -1324,18 +1551,55 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
else if (html_context->options->links_numbering)
put_link_number(html_context);
}
#ifdef CONFIG_UTF_8
cells =
#endif /* CONFIG_UTF_8 */
set_hline(html_context, chars, charslen, link_state);
if (link_state != LINK_STATE_NONE) {
process_link(html_context, link_state, chars, charslen);
#if 0
/* This all code is from utf8 branch */
#define is_drawing_subs_or_sups() \
((format.style.attr & AT_SUBSCRIPT \
&& html_context->options->display_subs) \
|| (format.style.attr & AT_SUPERSCRIPT \
&& html_context->options->display_sups))
/* We need to update the current @link_state because <sub> and
* <sup> tags will output to the canvas using an inner
* put_chars() call which results in their process_link() call
* will ``update'' the @link_state. */
if (link_state == LINK_STATE_NEW
&& (is_drawing_subs_or_sups()
|| update_after_subscript != renderer_context.subscript)) {
link_state = get_link_state(html_context);
}
#undef is_drawing_subs_or_sups
#endif
#ifdef CONFIG_UTF_8
process_link(html_context, link_state, chars, charslen,
cells);
#else
process_link(html_context, link_state, chars, charslen);
#endif /* CONFIG_UTF_8 */
}
#ifdef CONFIG_UTF_8
if (renderer_context.nowrap
&& part->cx + cells > overlap(par_format))
return;
part->cx += cells;
#else
if (renderer_context.nowrap
&& part->cx + charslen > overlap(par_format))
return;
part->cx += charslen;
#endif /* CONFIG_UTF_8 */
renderer_context.nobreak = 0;
if (!(html_context->options->wrap || html_is_preformatted())) {
@ -1351,7 +1615,11 @@ put_chars(struct html_context *html_context, unsigned char *chars, int charslen)
}
assert(charslen > 0);
#ifdef CONFIG_UTF_8
part->xa += cells;
#else
part->xa += charslen;
#endif /* CONFIG_UTF_8 */
int_lower_bound(&part->max_width, part->xa
+ par_format.leftmargin + par_format.rightmargin
- (chars[charslen - 1] == ' '
@ -1410,6 +1678,9 @@ end:
part->cx = -1;
part->xa = 0;
memset(part->spaces, 0, part->spaces_len);
#ifdef CONFIG_UTF_8
memset(part->char_width, 0, part->spaces_len);
#endif
}
static void
@ -1829,6 +2100,9 @@ format_html_part(struct html_context *html_context,
done_link_state_info();
mem_free_if(part->spaces);
#ifdef CONFIG_UTF_8
mem_free_if(part->char_width);
#endif
if (document) {
struct node *node = document->nodes.next;
@ -1912,6 +2186,9 @@ render_html_document(struct cache_entry *cached, struct document *document,
&document->cp,
&document->cp_status,
document->options.hard_assume);
#ifdef CONFIG_UTF_8
html_context->options->utf8 = is_cp_utf8(document->options.cp);
#endif /* CONFIG_UTF_8 */
if (title.length) {
document->title = convert_string(renderer_context.convert_table,

View File

@ -23,6 +23,10 @@ struct part {
unsigned char *spaces;
int spaces_len;
#ifdef CONFIG_UTF_8
unsigned char *char_width;
#endif
struct box box;

View File

@ -101,6 +101,9 @@ struct document_options {
unsigned int no_cache:1;
unsigned int gradual_rerendering:1;
#ifdef CONFIG_UTF_8
unsigned int utf8:1;
#endif /* CONFIG_UTF_8 */
/* Active link coloring */
/* This is mostly here to make use of this option cache so link
* drawing is faster. --jonas */

View File

@ -175,12 +175,12 @@ get_uri_length(unsigned char *line, int length)
static int
print_document_link(struct plain_renderer *renderer, int lineno,
unsigned char *line, int line_pos, int width,
int expanded, struct screen_char *pos)
int expanded, struct screen_char *pos, int cells)
{
struct document *document = renderer->document;
unsigned char *start = &line[line_pos];
int len = get_uri_length(start, width - line_pos);
int screen_column = line_pos + expanded;
int screen_column = cells + expanded;
struct link *new_link;
int link_end = line_pos + len;
unsigned char saved_char;
@ -226,209 +226,6 @@ print_document_link(struct plain_renderer *renderer, int lineno,
return len;
}
enum mode_16_256 {
COLOR_NONE,
COLOR_16_FOREGROUND,
COLOR_16_BACKGROUND,
COLOR_38,
COLOR_48,
COLOR_256_FOREGROUND,
COLOR_256_BACKGROUND
};
static int
change_colors(struct screen_char *template, unsigned char *line, int line_pos, int width, struct document *document)
{
unsigned char fg, bg, bold;
enum mode_16_256 color = COLOR_NONE;
unsigned char value = 0;
int start = 0;
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
fg = template->color[0];
bg = template->color[1];
#else
fg = template->color[0] & 15;
bg = template->color[0] >> 4;
#endif
bold = template->attr & SCREEN_ATTR_BOLD;
for (; line_pos < width; line_pos++) {
unsigned char ch = line[line_pos];
switch (color) {
case COLOR_NONE:
switch (ch) {
case '0':
bold = 0;
break;
case '1':
bold = SCREEN_ATTR_BOLD;
break;
case '3':
color = COLOR_16_FOREGROUND;
break;
case '4':
color = COLOR_16_BACKGROUND;
break;
case 'm':
goto end;
default:
break;
}
break;
case COLOR_16_FOREGROUND:
switch (ch) {
case '9':
fg = 7;
color = COLOR_NONE;
break;
case '8':
color = COLOR_38;
break;
case 'm':
goto end;
default:
if (ch >= '0' && ch <= '7') fg = ch - '0';
else goto end;
color = COLOR_NONE;
break;
}
break;
case COLOR_16_BACKGROUND:
switch (ch) {
case '9':
bg = 0;
color = COLOR_NONE;
break;
case '8':
color = COLOR_48;
break;
case 'm':
goto end;
default:
if (ch >= '0' && ch <= '7') bg = ch - '0';
else goto end;
color = COLOR_NONE;
break;
}
break;
case COLOR_38:
switch (ch) {
case '5':
start = 1;
value = 0;
color = COLOR_256_FOREGROUND;
break;
case 'm':
goto end;
case ';':
break;
default:
color = COLOR_NONE;
break;
}
break;
case COLOR_48:
switch (ch) {
case '5':
start = 1;
value = 0;
color = COLOR_256_BACKGROUND;
break;
case 'm':
goto end;
case ';':
break;
default:
color = COLOR_NONE;
break;
}
break;
case COLOR_256_FOREGROUND:
switch (ch) {
case ';':
case 'm':
if (start) {
start = 0;
value = 0;
} else {
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
#ifdef CONFIG_88_COLORS
if (document->options.color_mode == COLOR_MODE_88) fg = value;
#endif
#ifdef CONFIG_256_COLORS
if (document->options.color_mode == COLOR_MODE_256) fg = value;
#endif
#endif
color = COLOR_NONE;
value = 0;
}
if (ch == 'm') goto end;
break;
default:
if (ch >= '0' && ch <= '9') value *= 10 + ch - '0';
else goto end;
break;
}
break;
case COLOR_256_BACKGROUND:
switch (ch) {
case ';':
case 'm':
if (start) {
start = 0;
value = 0;
} else {
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
#ifdef CONFIG_88_COLORS
if (document->options.color_mode == COLOR_MODE_88) bg = value;
#endif
#ifdef CONFIG_256_COLORS
if (document->options.color_mode == COLOR_MODE_256) bg = value;
#endif
#endif
color = COLOR_NONE;
value = 0;
}
if (ch == 'm') goto end;
break;
default:
if (ch >= '0' && ch <= '9') value *= 10 + ch - '0';
else goto end;
break;
}
break;
}
}
end:
#if defined(CONFIG_88_COLORS) || defined(CONFIG_256_COLORS)
#ifdef CONFIG_88_COLORS
if (document->options.color_mode == COLOR_MODE_88) {
TERM_COLOR_FOREGROUND(template->color) = fg;
TERM_COLOR_BACKGROUND(template->color) = bg;
}
#endif
#ifdef CONFIG_256_COLORS
if (document->options.color_mode == COLOR_MODE_256) {
TERM_COLOR_FOREGROUND(template->color) = fg;
TERM_COLOR_BACKGROUND(template->color) = bg;
}
#endif
#endif
if (document->options.color_mode == COLOR_MODE_16) {
fg |= bold;
set_term_color16(template, document->options.color_flags, fg, bg);
}
return line_pos;
}
static inline int
add_document_line(struct plain_renderer *renderer,
unsigned char *line, int line_width)
@ -437,6 +234,10 @@ add_document_line(struct plain_renderer *renderer,
struct screen_char *template = &renderer->template;
struct screen_char saved_renderer_template = *template;
struct screen_char *pos, *startpos;
#ifdef CONFIG_UTF_8
int utf8 = document->options.utf8;
#endif /* CONFIG_UTF_8 */
int cells = 0;
int lineno = renderer->lineno;
int expanded = 0;
int width = line_width;
@ -448,13 +249,31 @@ add_document_line(struct plain_renderer *renderer,
if (!line) return 0;
/* Now expand tabs */
for (line_pos = 0; line_pos < width; line_pos++) {
for (line_pos = 0; line_pos < width;) {
unsigned char line_char = line[line_pos];
int charlen = 1;
int cell = 1;
#ifdef CONFIG_UTF_8
unicode_val_T data;
if (utf8) {
unsigned char *line_char2 = &line[line_pos];
charlen = utf8charlen(&line_char);
data = utf_8_to_unicode(&line_char2, &line[width]);
if (data == UCS_NO_CHAR) {
line_pos += charlen;
continue;
}
cell = unicode_to_cell(data);
}
#endif /* CONFIG_UTF_8 */
if (line_char == ASCII_TAB
&& (line_pos + 1 == width
|| line[line_pos + 1] != ASCII_BS)) {
int tab_width = 7 - ((line_pos + expanded) & 7);
&& (line_pos + charlen == width
|| line[line_pos + charlen] != ASCII_BS)) {
int tab_width = 7 - ((cells + expanded) & 7);
expanded += tab_width;
} else if (line_char == ASCII_BS) {
@ -475,6 +294,8 @@ add_document_line(struct plain_renderer *renderer,
expanded--;
#endif
}
line_pos += charlen;
cells += cell;
}
assert(expanded >= 0);
@ -485,28 +306,55 @@ add_document_line(struct plain_renderer *renderer,
return 0;
}
cells = 0;
expanded = 0;
for (line_pos = 0; line_pos < width; line_pos++) {
for (line_pos = 0; line_pos < width;) {
unsigned char line_char = line[line_pos];
unsigned char next_char, prev_char;
int charlen = 1;
int cell = 1;
#ifdef CONFIG_UTF_8
unicode_val_T data;
prev_char = line_pos > 0 ? line[line_pos - 1] : '\0';
next_char = (line_pos + 1 < width) ? line[line_pos + 1]
: '\0';
if (utf8) {
unsigned char *line_char2 = &line[line_pos];
charlen = utf8charlen(&line_char);
data = utf_8_to_unicode(&line_char2, &line[width]);
switch (line_char) {
case 27:
if (next_char != '[') goto normal;
line_pos += 2;
line_pos = change_colors(&saved_renderer_template, line, line_pos, width, document);
*template = saved_renderer_template;
break;
case ASCII_BS:
if (!(expanded + line_pos)) {
/* We've backspaced to the start of the line */
if (data == UCS_NO_CHAR) {
line_pos += charlen;
continue;
}
cell = unicode_to_cell(data);
}
#endif /* CONFIG_UTF_8 */
prev_char = line_pos > 0 ? line[line_pos - 1] : '\0';
next_char = (line_pos + charlen < width) ?
line[line_pos + charlen] : '\0';
/* Do not expand tabs that precede back-spaces; this saves the
* back-space code some trouble. */
if (line_char == ASCII_TAB && next_char != ASCII_BS) {
int tab_width = 7 - ((cells + expanded) & 7);
expanded += tab_width;
template->data = ' ';
do
copy_screen_chars(pos++, template, 1);
while (tab_width--);
*template = saved_renderer_template;
} else if (line_char == ASCII_BS) {
#if 0
if (!(expanded + cells)) {
/* We've backspaced to the start of the line */
continue;
}
#endif
if (pos > startpos)
pos--; /* Backspace */
@ -516,8 +364,8 @@ add_document_line(struct plain_renderer *renderer,
/* x^H_ becomes _^Hx */
if (line_pos - 1 >= 0)
line[line_pos - 1] = next_char;
if (line_pos + 1 < width)
line[line_pos + 1] = prev_char;
if (line_pos + charlen < width)
line[line_pos + charlen] = prev_char;
/* Go back and reparse the swapped characters */
if (line_pos - 2 >= 0)
@ -562,26 +410,7 @@ add_document_line(struct plain_renderer *renderer,
/* Handle _^Hx^Hx as both bold and underlined */
if (template->attr)
template->attr |= pos->attr;
break;
case ASCII_TAB:
/* Do not expand tabs that precede back-spaces; this saves the
* back-space code some trouble. */
if (next_char != ASCII_BS) {
int tab_width = 7 - ((line_pos + expanded) & 7);
expanded += tab_width;
template->data = ' ';
do
copy_screen_chars(pos++, template, 1);
while (tab_width--);
*template = saved_renderer_template;
break;
}
default:
normal:
{
} else {
int added_chars = 0;
if (document->options.plain_display_links
@ -596,28 +425,54 @@ normal:
line_pos,
width,
expanded,
pos);
pos, cells);
}
if (added_chars) {
line_pos += added_chars - 1;
pos += added_chars;
} else {
if (!isscreensafe(line_char) && line_char != 27)
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *text = &line[line_pos];
unicode_val_T data =
utf_8_to_unicode(&text,
&line[width]);
if (data == UCS_NO_CHAR) {
line_pos += charlen;
continue;
}
template->data = (unicode_val_T)data;
copy_screen_chars(pos++, template, 1);
if (unicode_to_cell(data) == 2) {
template->data = UCS_NO_CHAR;
copy_screen_chars(pos++,
template, 1);
cell++;
}
} else
#endif /* CONFIG_UTF_8 */
{
if (!isscreensafe(line_char))
line_char = '.';
template->data = line_char;
copy_screen_chars(pos++, template, 1);
/* Detect copy of nul chars to screen, this
* should not occur. --Zas */
/* Detect copy of nul chars to screen,
* this should not occur. --Zas */
assert(line_char);
}
}
*template = saved_renderer_template;
}
}
}
line_pos += charlen;
cells += cell;
}
mem_free(line);
realloc_line(document, pos - startpos, lineno);
@ -664,19 +519,20 @@ add_document_lines(struct plain_renderer *renderer)
int length = renderer->length;
int was_empty_line = 0;
int was_wrapped = 0;
#ifdef CONFIG_UTF_8
int utf8 = is_cp_utf8(renderer->document->cp);
#endif
for (; length > 0; renderer->lineno++) {
unsigned char *xsource;
int width, added, only_spaces = 1, spaces = 0, was_spaces = 0;
int last_space = 0;
int tab_spaces = 0;
int step = 0;
int cells = 0;
/* End of line detection: We handle \r, \r\n and \n types. */
for (width = 0;
width + tab_spaces < renderer->max_width
&& width < length;
width++) {
for (width = 0; (width < length) &&
(cells < renderer->max_width);) {
if (source[width] == ASCII_CR)
step++;
if (source[width + step] == ASCII_LF)
@ -695,6 +551,22 @@ add_document_lines(struct plain_renderer *renderer)
only_spaces = 0;
was_spaces = 0;
}
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *text = &source[width];
unicode_val_T data = utf_8_to_unicode(&text,
&source[length]);
if (data == UCS_NO_CHAR) return;
cells += unicode_to_cell(data);
width += utf8charlen(&source[width]);
} else
#endif /* CONFIG_UTF_8 */
{
cells++;
width++;
}
}
if (only_spaces && step) {
@ -722,6 +594,7 @@ add_document_lines(struct plain_renderer *renderer)
width -= was_spaces;
step += was_spaces;
}
if (!step && (width < length) && last_space) {
width = last_space;
step = 1;
@ -777,6 +650,9 @@ render_plain_document(struct cache_entry *cached, struct document *document,
document->bgcolor = document->options.default_bg;
document->width = 0;
#ifdef CONFIG_UTF_8
document->options.utf8 = is_cp_utf8(document->options.cp);
#endif /* CONFIG_UTF_8 */
/* Setup the style */
init_template(&renderer.template, &document->options);

View File

@ -345,9 +345,15 @@ render_document(struct view_state *vs, struct document_view *doc_view,
}
document->title = get_uri_string(document->uri, components);
if (document->title)
if (document->title) {
#ifdef CONFIG_UTF_8
if (doc_view->document->options.utf8)
decode_uri(document->title);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(document->title);
}
}
#ifdef CONFIG_CSS
document->css_magic = get_document_css_magic(document);

View File

@ -140,6 +140,14 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
int s;
if (u < 128) return strings[u];
to &= ~SYSTEM_CHARSET_FLAG;
#ifdef CONFIG_UTF_8
if (codepages[to].table == table_utf_8)
return encode_utf_8(u);
#endif /* CONFIG_UTF_8 */
/* To mark non breaking spaces, we use a special char NBSP_CHAR. */
if (u == 0xa0) return no_nbsp_hack ? " " : NBSP_CHAR_STRING;
if (u == 0xad) return "";
@ -151,7 +159,6 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
return u2cp_(strange, to, no_nbsp_hack);
}
to &= ~SYSTEM_CHARSET_FLAG;
for (j = 0; codepages[to].table[j].c; j++)
if (codepages[to].table[j].u == u)
@ -165,8 +172,13 @@ u2cp_(unicode_val_T u, int to, int no_nbsp_hack)
static unsigned char utf_buffer[7];
#ifdef CONFIG_UTF_8
inline unsigned char *
encode_utf_8(unicode_val_T u)
#else
static unsigned char *
encode_utf_8(unicode_val_T u)
#endif /* CONFIG_UTF_8 */
{
memset(utf_buffer, 0, 7);
@ -200,6 +212,252 @@ encode_utf_8(unicode_val_T u)
return utf_buffer;
}
#ifdef CONFIG_UTF_8
/* Number of bytes utf8 character indexed by first byte. Illegal bytes are
* equal ones and handled different. */
static char utf8char_len_tab[256] = {
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1,
};
inline int utf8charlen(const unsigned char *p)
{
return p ? utf8char_len_tab[*p] : 0;
}
inline int
strlen_utf8(unsigned char **str)
{
unsigned char *s = *str;
unsigned char *end = strchr(s, '\0');
int x;
int len;
for (x = 0;; x++, s += len) {
len = utf8charlen(s);
if (s + len > end) break;
}
*str = s;
return x;
}
#define utf8_issingle(p) (((p) & 0x80) == 0)
#define utf8_islead(p) (utf8_issingle(p) || ((p) & 0xc0) == 0xc0)
/* Start from @current and move back to @pos char. This pointer return. The
* most left pointer is @start. */
inline unsigned char *
utf8_prevchar(unsigned char *current, int pos, unsigned char *start)
{
if (current == NULL || start == NULL || pos < 0)
return NULL;
while (pos > 0 && current != start) {
current--;
if (utf8_islead(*current))
pos--;
}
return current;
}
/* Count number of standard terminal cells needed for displaying UTF-8
* character. */
int
utf8_char2cells(unsigned char *utf8_char, unsigned char *end)
{
unicode_val_T u;
if (end == NULL)
end = strchr(utf8_char, '\0');
if(!utf8_char || !end)
return -1;
u = utf_8_to_unicode(&utf8_char, end);
return unicode_to_cell(u);
}
/* Count number of standard terminal cells needed for displaying string
* with UTF-8 characters. */
int
utf8_ptr2cells(unsigned char *string, unsigned char *end)
{
int charlen, cell, cells = 0;
if (end == NULL)
end = strchr(string, '\0');
if(!string || !end)
return -1;
do {
charlen = utf8charlen(string);
if (string + charlen > end)
break;
cell = utf8_char2cells(string, end);
if (cell < 0)
return -1;
cells += cell;
string += charlen;
} while (1);
return cells;
}
/* Count number of characters in string. */
int
utf8_ptr2chars(unsigned char *string, unsigned char *end)
{
int charlen, chars = 0;
if (end == NULL)
end = strchr(string, '\0');
if(!string || !end)
return -1;
do {
charlen = utf8charlen(string);
if (string + charlen > end)
break;
chars++;
string += charlen;
} while (1);
return chars;
}
/*
* Count number of bytes from begining of the string needed for displaying
* specified number of cells.
*/
int
utf8_cells2bytes(unsigned char *string, int max_cells, unsigned char *end)
{
unsigned int bytes = 0, cells = 0;
assert(max_cells>=0);
if (end == NULL)
end = strchr(string, '\0');
if(!string || !end)
return -1;
do {
int cell = utf8_char2cells(&string[bytes], end);
if (cell < 0)
return -1;
cells += cell;
if (cells > max_cells)
break;
bytes += utf8charlen(&string[bytes]);
if (string + bytes > end) {
bytes = end - string;
break;
}
} while(1);
return bytes;
}
/*
* Find out number of standard terminal collumns needed for displaying symbol
* (glyph) which represents Unicode character c.
* TODO: Use wcwidth when it is available.
*
* @return 2 for double-width glyph, 1 for others.
* TODO: May be extended to return 0 for zero-width glyphs
* (like composing, maybe unprintable too).
*/
inline int
unicode_to_cell(unicode_val_T c)
{
if (c >= 0x1100
&& (c <= 0x115f /* Hangul Jamo */
|| c == 0x2329
|| c == 0x232a
|| (c >= 0x2e80 && c <= 0xa4cf
&& c != 0x303f) /* CJK ... Yi */
|| (c >= 0xac00 && c <= 0xd7a3) /* Hangul Syllables */
|| (c >= 0xf900 && c <= 0xfaff) /* CJK Compatibility
Ideographs */
|| (c >= 0xfe30 && c <= 0xfe6f) /* CJK Compatibility Forms */
|| (c >= 0xff00 && c <= 0xff60) /* Fullwidth Forms */
|| (c >= 0xffe0 && c <= 0xffe6)
|| (c >= 0x20000 && c <= 0x2fffd)
|| (c >= 0x30000 && c <= 0x3fffd)))
return 2;
return 1;
}
inline unicode_val_T
utf_8_to_unicode(unsigned char **string, unsigned char *end)
{
unsigned char *str = *string;
unicode_val_T u;
int length;
length = utf8char_len_tab[str[0]];
if (str + length > end) {
return UCS_NO_CHAR;
}
switch (length) {
case 1:
u = str[0];
break;
case 2:
u = (str[0] & 0x1f) << 6;
u += (str[1] & 0x3f);
break;
case 3:
u = (str[0] & 0x0f) << 12;
u += ((str[1] & 0x3f) << 6);
u += (str[2] & 0x3f);
break;
case 4:
u = (str[0] & 0x0f) << 18;
u += ((str[1] & 0x3f) << 12);
u += ((str[2] & 0x3f) << 6);
u += (str[3] & 0x3f);
break;
case 5:
u = (str[0] & 0x0f) << 24;
u += ((str[1] & 0x3f) << 18);
u += ((str[2] & 0x3f) << 12);
u += ((str[3] & 0x3f) << 6);
u += (str[4] & 0x3f);
break;
case 6:
default:
u = (str[0] & 0x01) << 30;
u += ((str[1] & 0x3f) << 24);
u += ((str[2] & 0x3f) << 18);
u += ((str[3] & 0x3f) << 12);
u += ((str[4] & 0x3f) << 6);
u += (str[5] & 0x3f);
break;
}
*string = str + length;
return u;
}
#endif /* CONFIG_UTF_8 */
/* This slow and ugly code is used by the terminal utf_8_io */
unsigned char *
cp2utf_8(int from, int c)
@ -430,11 +688,18 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
static struct entity_cache entity_cache[ENTITY_CACHE_MAXLEN][ENTITY_CACHE_SIZE];
static unsigned int nb_entity_cache[ENTITY_CACHE_MAXLEN];
static int first_time = 1;
unsigned int slen;
unsigned int slen = 0;
unsigned char *result = NULL;
if (strlen <= 0) return NULL;
#ifdef CONFIG_UTF_8
/* TODO: caching UTF-8 */
encoding &= ~SYSTEM_CHARSET_FLAG;
if (codepages[encoding].table == table_utf_8)
goto skip;
#endif /* CONFIG_UTF_8 */
if (first_time) {
memset(&nb_entity_cache, 0, ENTITY_CACHE_MAXLEN * sizeof(unsigned int));
first_time = 0;
@ -488,7 +753,9 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
fprintf(stderr, "miss\n");
#endif
}
#ifdef CONFIG_UTF_8
skip:
#endif /* CONFIG_UTF_8 */
if (*str == '#') { /* Numeric entity. */
int l = (int) strlen;
unsigned char *st = (unsigned char *) str;
@ -540,6 +807,11 @@ get_entity_string(const unsigned char *str, const int strlen, int encoding)
if (element) result = u2cp(element->c, encoding);
}
#ifdef CONFIG_UTF_8
if (codepages[encoding].table == table_utf_8) {
return result;
}
#endif /* CONFIG_UTF_8 */
end:
/* Take care of potential buffer overflow. */
if (strlen < sizeof(entity_cache[slen][0].str)) {
@ -865,7 +1137,7 @@ get_cp_mime_name(int cp_index)
}
int
is_cp_special(int cp_index)
is_cp_utf8(int cp_index)
{
cp_index &= ~SYSTEM_CHARSET_FLAG;
return codepages[cp_index].table == table_utf_8;

View File

@ -51,8 +51,21 @@ unsigned char *convert_string(struct conv_table *convert_table,
int get_cp_index(unsigned char *);
unsigned char *get_cp_name(int);
unsigned char *get_cp_mime_name(int);
int is_cp_special(int);
int is_cp_utf8(int);
void free_conv_table(void);
#ifdef CONFIG_UTF_8
inline unsigned char *encode_utf_8(unicode_val_T);
inline unsigned char *utf8_prevchar(unsigned char *, int, unsigned char *);
inline int utf8charlen(const unsigned char *);
int utf8_char2cells(unsigned char *, unsigned char *);
int utf8_ptr2cells(unsigned char *, unsigned char *);
int utf8_ptr2chars(unsigned char *, unsigned char *);
int utf8_cells2bytes(unsigned char *, int, unsigned char *);
inline int unicode_to_cell(unicode_val_T);
inline int strlen_utf8(unsigned char **);
inline unicode_val_T utf_8_to_unicode(unsigned char **, unsigned char *);
#endif /* CONFIG_UTF_8 */
unsigned char *cp2utf_8(int, int);
unsigned char *u2cp_(unicode_val_T, int, int no_nbsp_hack);

File diff suppressed because it is too large Load Diff

View File

@ -118,6 +118,9 @@ get_dyn_full_version(struct terminal *term, int more)
#endif
#ifndef CONFIG_MOUSE
comma, _("No mouse", term),
#endif
#ifdef CONFIG_UTF_8
comma, "UTF-8",
#endif
comma,
NULL

View File

@ -574,6 +574,11 @@ bittorrent_message_dialog(struct session *ses, void *data)
uristring = get_uri_string(message->uri, URI_PUBLIC);
if (uristring) {
#ifdef CONFIG_UTF_8
if (ses->tab->term->utf8)
decode_uri(uristring);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(uristring);
add_format_to_string(&string,
_("Unable to retrieve %s", ses->tab->term),
@ -719,6 +724,11 @@ bittorrent_query_callback(void *data, enum connection_state state,
/* Let's make the filename pretty for display & save */
/* TODO: The filename can be the empty string here. See bug 396. */
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri_string(&filename);
else
#endif /* CONFIG_UTF_8 */
decode_uri_string_for_display(&filename);
}

View File

@ -649,6 +649,10 @@ init_gopher_index_cache_entry(struct connection *conn)
return S_OUT_OF_MEM;
where = get_uri_string(conn->uri, URI_PUBLIC);
/* TODO: Use different function when using UTF-8
* in terminal (decode_uri_for_display replaces
* bytes of UTF-8 characters width '*'). */
if (where) decode_uri_for_display(where);
add_format_to_string(&buffer,

View File

@ -4,7 +4,6 @@
#include "config.h"
#endif
#include "scripting/python/core.h"
#include <Python.h>
#include <stdio.h>
@ -14,24 +13,91 @@
#include "config/home.h"
#include "main/module.h"
#include "scripting/scripting.h"
#include "scripting/python/core.h"
#include "scripting/python/python.h"
#include "util/env.h"
#include "util/file.h"
#include "util/string.h"
PyObject *pDict, *pModule;
PyObject *pDict = NULL, *pModule = NULL;
/* Error reporting. */
void
alert_python_error(struct session *ses)
{
unsigned char *msg = "(no traceback available)";
PyObject *err_type = NULL, *err_value = NULL, *err_traceback = NULL;
PyObject *tb_module = NULL;
PyObject *tb_dict;
PyObject *format_function;
PyObject *msg_list = NULL;
PyObject *empty_string = NULL;
PyObject *join_method = NULL;
PyObject *msg_string = NULL;
unsigned char *temp;
/*
* Retrieve the current error indicator and use the format_exception()
* function in Python's traceback module to produce an informative
* error message. It returns a list of Python string objects.
*/
PyErr_Fetch(&err_type, &err_value, &err_traceback);
PyErr_NormalizeException(&err_type, &err_value, &err_traceback);
if (!err_traceback) goto end;
tb_module = PyImport_ImportModule("traceback");
if (!tb_module) goto end;
tb_dict = PyModule_GetDict(tb_module);
format_function = PyDict_GetItemString(tb_dict, "format_exception");
if (!format_function || !PyCallable_Check(format_function)) goto end;
msg_list = PyObject_CallFunction(format_function, "OOO",
err_type, err_value, err_traceback);
if (!msg_list) goto end;
/*
* Use the join() method of an empty Python string to join the list
* of strings into one Python string containing the entire error
* message. Then get the contents of the Python string.
*/
empty_string = PyString_FromString("");
if (!empty_string) goto end;
join_method = PyObject_GetAttrString(empty_string, "join");
if (!join_method || !PyCallable_Check(join_method)) goto end;
msg_string = PyObject_CallFunction(join_method, "O", msg_list);
if (!msg_string) goto end;
temp = (unsigned char *)PyString_AsString(msg_string);
if (temp) msg = temp;
end:
report_scripting_error(&python_scripting_module, ses, msg);
Py_XDECREF(err_type);
Py_XDECREF(err_value);
Py_XDECREF(err_traceback);
Py_XDECREF(tb_module);
Py_XDECREF(msg_list);
Py_XDECREF(empty_string);
Py_XDECREF(join_method);
Py_XDECREF(msg_string);
/* In case another error occurred while reporting the original error: */
PyErr_Clear();
}
void
cleanup_python(struct module *module)
{
if (Py_IsInitialized()) {
if (pModule) {
Py_DECREF(pModule);
}
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
Py_XDECREF(pDict);
Py_XDECREF(pModule);
Py_Finalize();
}
}
@ -44,15 +110,25 @@ init_python(struct module *module)
if (!python_path) return;
env_set("PYTHONPATH", python_path, -1);
mem_free(python_path);
/* Treat warnings as errors so they can be caught and handled;
* otherwise they would be printed to stderr.
*
* NOTE: PySys_ResetWarnOptions() and PySys_AddWarnOption() have been
* available and stable for many years but they're not officially
* documented as part of Python's public API, so in theory these two
* functions might no longer be available in some hypothetical future
* version of Python. */
PySys_ResetWarnOptions();
PySys_AddWarnOption("error");
Py_Initialize();
pModule = PyImport_ImportModule("hooks");
if (pModule) {
pDict = PyModule_GetDict(pModule);
Py_INCREF(pDict);
} else {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
alert_python_error(NULL);
}
}

View File

@ -3,7 +3,9 @@
#define EL__SCRIPTING_PYTHON_CORE_H
struct module;
struct session;
void alert_python_error(struct session *ses);
void init_python(struct module *module);
void cleanup_python(struct module *module);

View File

@ -32,29 +32,29 @@ do_script_hook_goto_url(struct session *ses, unsigned char **url)
if (pFunc && PyCallable_Check(pFunc)) {
PyObject *pValue;
unsigned char *str;
unsigned char *current_url;
if (!ses || !have_location(ses)) {
str = NULL;
current_url = NULL;
} else {
str = struri(cur_loc(ses)->vs.uri);
current_url = struri(cur_loc(ses)->vs.uri);
}
pValue = PyObject_CallFunction(pFunc, "ss", *url, str);
if (pValue && (pValue != Py_None)) {
const unsigned char *res = PyString_AsString(pValue);
if (res) {
unsigned char *new_url = stracpy((unsigned char *)res);
pValue = PyObject_CallFunction(pFunc, "ss", *url, current_url);
if (pValue) {
if (pValue != Py_None) {
const unsigned char *str;
unsigned char *new_url;
str = PyString_AsString(pValue);
if (str) {
new_url = stracpy((unsigned char *)str);
if (new_url) mem_free_set(url, new_url);
}
}
Py_DECREF(pValue);
} else {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
alert_python_error(ses);
}
}
}
@ -72,26 +72,26 @@ script_hook_goto_url(va_list ap, void *data)
}
static void
do_script_hook_follow_url(unsigned char **url)
do_script_hook_follow_url(struct session *ses, unsigned char **url)
{
PyObject *pFunc = PyDict_GetItemString(pDict, "follow_url_hook");
if (pFunc && PyCallable_Check(pFunc)) {
PyObject *pValue = PyObject_CallFunction(pFunc, "s", *url);
if (pValue && (pValue != Py_None)) {
const unsigned char *str = PyString_AsString(pValue);
if (pValue) {
if (pValue != Py_None) {
const unsigned char *str;
unsigned char *new_url;
str = PyString_AsString(pValue);
if (str) {
new_url = stracpy((unsigned char *)str);
if (new_url) mem_free_set(url, new_url);
}
}
Py_DECREF(pValue);
} else {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
alert_python_error(ses);
}
}
}
@ -100,15 +100,17 @@ static enum evhook_status
script_hook_follow_url(va_list ap, void *data)
{
unsigned char **url = va_arg(ap, unsigned char **);
struct session *ses = va_arg(ap, struct session *);
if (pDict && *url)
do_script_hook_follow_url(url);
do_script_hook_follow_url(ses, url);
return EVENT_HOOK_STATUS_NEXT;
}
static void
do_script_hook_pre_format_html(unsigned char *url, struct cache_entry *cached,
do_script_hook_pre_format_html(struct session *ses, unsigned char *url,
struct cache_entry *cached,
struct fragment *fragment)
{
PyObject *pFunc = PyDict_GetItemString(pDict, "pre_format_html_hook");
@ -118,21 +120,21 @@ do_script_hook_pre_format_html(unsigned char *url, struct cache_entry *cached,
fragment->data,
fragment->length);
if (pValue && (pValue != Py_None)) {
const unsigned char *str = PyString_AsString(pValue);
if (pValue) {
if (pValue != Py_None) {
const unsigned char *str;
int len;
str = PyString_AsString(pValue);
if (str) {
int len = PyString_Size(pValue); /* strlen(str); */
len = PyString_Size(pValue);
add_fragment(cached, 0, str, len);
normalize_cache_entry(cached, len);
}
}
Py_DECREF(pValue);
} else {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
alert_python_error(ses);
}
}
}
@ -146,7 +148,7 @@ script_hook_pre_format_html(va_list ap, void *data)
unsigned char *url = struri(cached->uri);
if (pDict && ses && url && cached->length && *fragment->data)
do_script_hook_pre_format_html(url, cached, fragment);
do_script_hook_pre_format_html(ses, url, cached, fragment);
return EVENT_HOOK_STATUS_NEXT;
}
@ -159,20 +161,21 @@ do_script_hook_get_proxy(unsigned char **new_proxy_url, unsigned char *url)
if (pFunc && PyCallable_Check(pFunc)) {
PyObject *pValue = PyObject_CallFunction(pFunc, "s", url);
if (pValue && (pValue != Py_None)) {
const unsigned char *str = PyString_AsString(pValue);
if (pValue) {
if (pValue != Py_None) {
const unsigned char *str;
unsigned char *new_url;
str = PyString_AsString(pValue);
if (str) {
unsigned char *new_url = stracpy((unsigned char *)str);
if (new_url) mem_free_set(new_proxy_url, new_url);
new_url = stracpy((unsigned char *)str);
if (new_url) mem_free_set(new_proxy_url,
new_url);
}
}
Py_DECREF(pValue);
} else {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
alert_python_error(NULL);
}
}
}
@ -198,14 +201,9 @@ do_script_hook_quit(void)
PyObject *pValue = PyObject_CallFunction(pFunc, NULL);
if (pValue) {
if (pValue != Py_None) {
Py_DECREF(pValue);
}
} else {
if (PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
alert_python_error(NULL);
}
}
}

View File

@ -24,10 +24,14 @@
#include "scripting/ruby/ruby.h"
#include "scripting/smjs/smjs.h"
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
/* Error reporting. */
#if defined(CONFIG_SCRIPTING_RUBY) || defined(CONFIG_SCRIPTING_SPIDERMONKEY)
#if defined(CONFIG_SCRIPTING_RUBY) || defined(CONFIG_SCRIPTING_SPIDERMONKEY) || defined(CONFIG_SCRIPTING_PYTHON)
void
report_scripting_error(struct module *module, struct session *ses,
unsigned char *msg)
@ -38,6 +42,7 @@ report_scripting_error(struct module *module, struct session *ses,
if (!ses) {
if (list_empty(terminals)) {
usrerror("[%s error] %s", module->name, msg);
sleep(3);
return;
}

View File

@ -1134,6 +1134,11 @@ do_type_query(struct type_query *type_query, unsigned char *ct, struct mime_hand
/* Let's make the filename pretty for display & save */
/* TODO: The filename can be the empty string here. See bug 396. */
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri_string(&filename);
else
#endif /* CONFIG_UTF_8 */
decode_uri_string_for_display(&filename);
}

View File

@ -268,6 +268,11 @@ print_error_dialog(struct session *ses, enum connection_state state,
uristring = uri ? get_uri_string(uri, URI_PUBLIC) : NULL;
if (uristring) {
#ifdef CONFIG_UTF_8
if (ses->tab->term->utf8)
decode_uri(uristring);
else
#endif /* CONFIG_UTF_8 */
decode_uri_for_display(uristring);
add_format_to_string(&msg,
_("Unable to retrieve %s", ses->tab->term),

View File

@ -7,6 +7,7 @@
#include "elinks.h"
#include "config/options.h"
#include "intl/charsets.h"
#include "terminal/color.h"
#include "terminal/draw.h"
#include "terminal/screen.h"
@ -102,13 +103,30 @@ draw_char_color(struct terminal *term, int x, int y, struct color_pair *color)
}
void
#ifdef CONFIG_UTF_8
draw_char_data(struct terminal *term, int x, int y, unicode_val_T data)
#else
draw_char_data(struct terminal *term, int x, int y, unsigned char data)
#endif /* CONFIG_UTF_8 */
{
struct screen_char *screen_char = get_char(term, x, y);
if (!screen_char) return;
screen_char->data = data;
#ifdef CONFIG_UTF_8
#ifdef CONFIG_DEBUG
/* Detect attempt to draw double-width char on the last
* column of terminal. */
if (unicode_to_cell(data) == 2 && x + 1 > term->width)
INTERNAL("Attempt to draw double-width glyph on last column!");
#endif /* CONFIG_DEBUG */
if (data == UCS_NO_CHAR)
screen_char->attr = 0;
#endif /* CONFIG_UTF_8 */
set_screen_dirty(term->screen, y, y);
}
@ -127,6 +145,38 @@ draw_line(struct terminal *term, int x, int y, int l, struct screen_char *line)
size = int_min(l, term->width - x);
if (size == 0) return;
#ifdef CONFIG_UTF_8
if (term->utf8) {
struct screen_char *sc;
if (line->data == UCS_NO_CHAR && x == 0) {
unicode_val_T data_save;
sc = line;
data_save = sc->data;
sc->data = ' ';
copy_screen_chars(screen_char, line, 1);
sc->data = data_save;
size--;
line++;
screen_char++;
}
/* Instead of displaying double-width character at last column
* display only space. */
if (size - 1 > 0 && unicode_to_cell(line[size - 1].data) == 2) {
unicode_val_T data_save;
sc = &line[size - 1];
data_save = sc->data;
sc->data = ' ';
copy_screen_chars(screen_char, line, size);
sc->data = data_save;
} else {
copy_screen_chars(screen_char, line, size);
}
} else
#endif
copy_screen_chars(screen_char, line, size);
set_screen_dirty(term->screen, y, y);
}
@ -198,10 +248,88 @@ draw_border(struct terminal *term, struct box *box,
set_screen_dirty(term->screen, borderbox.y, borderbox.y + borderbox.height);
}
#ifdef CONFIG_UTF_8
/* Checks cells left and right to the box for broken double-width chars.
* Replace it with ' '.
* 1+---+3
* 1|box|##4
* 1| |##4
* 1| |##4
* 1+---+##4
* 2#####4
* 1,2,3,4 - needs to be checked, # - shadow , +,-,| - border
*/
void
fix_dwchar_around_box(struct terminal *term, struct box *box, int border,
int shadow_width, int shadow_height)
{
struct screen_char *schar;
int height, x, y;
if (!term->utf8)
return;
/* 1 */
x = box->x - border - 1;
if (x > 0) {
y = box->y - border;
height = box->height + 2 * border;
schar = get_char(term, x, y);
for (;height--; schar += term->width)
if (unicode_to_cell(schar->data) == 2)
schar->data = ' ';
}
/* 2 */
x = box->x - border + shadow_width - 1;
if (x > 0 && x < term->width) {
y = box->y + border + box->height;
height = shadow_height;
schar = get_char(term, x, y);
for (;height--; schar += term->width)
if (unicode_to_cell(schar->data) == 2)
schar->data = ' ';
}
/* 3 */
x = box->x + box->width + border;
if (x < term->width) {
y = box->y - border;
height = shadow_height;
schar = get_char(term, x, y);
for (;height--; schar += term->width)
if (schar->data == UCS_NO_CHAR)
schar->data = ' ';
}
/* 4 */
x = box->x + box->width + border + shadow_width;
if (x < term->width) {
y = box->y - border + shadow_height;
height = box->height + 2 * border;
schar = get_char(term, x, y);
for (;height--; schar += term->width)
if (schar->data == UCS_NO_CHAR)
schar->data = ' ';
}
}
#endif
#ifdef CONFIG_UTF_8
void
draw_char(struct terminal *term, int x, int y,
unicode_val_T data, enum screen_char_attr attr,
struct color_pair *color)
#else
void
draw_char(struct terminal *term, int x, int y,
unsigned char data, enum screen_char_attr attr,
struct color_pair *color)
#endif /* CONFIG_UTF_8 */
{
struct screen_char *screen_char = get_char(term, x, y);
@ -277,6 +405,80 @@ draw_shadow(struct terminal *term, struct box *box,
draw_box(term, &dbox, ' ', 0, color);
}
#ifdef CONFIG_UTF_8
static void
draw_text_utf8(struct terminal *term, int x, int y,
unsigned char *text, int length,
enum screen_char_attr attr, struct color_pair *color)
{
struct screen_char *start, *pos;
unsigned char *end = text + length;
unicode_val_T data;
assert(text && length >= 0);
if_assert_failed return;
if (length <= 0) return;
if (x >= term->width) return;
data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) return;
start = get_char(term, x, y);
if (color) {
start->attr = attr;
set_term_color(start, color, 0,
get_opt_int_tree(term->spec, "colors"));
}
if (start->data == UCS_NO_CHAR && x - 1 > 0)
draw_char_data(term, x - 1, y, ' ');
pos = start;
if (unicode_to_cell(data) == 2) {
/* Is there enough room for whole double-width char? */
if (x + 1 < term->width) {
pos->data = data;
pos++;
x++;
pos->data = UCS_NO_CHAR;
pos->attr = 0;
} else {
pos->data = (unicode_val_T)' ';
}
} else {
pos->data = data;
}
pos++;
x++;
for (; x < term->width; x++, pos++) {
data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) break;
if (color) copy_screen_chars(pos, start, 1);
if (unicode_to_cell(data) == 2) {
/* Is there enough room for whole double-width char? */
if (x + 1 < term->width) {
pos->data = data;
x++;
pos++;
pos->data = UCS_NO_CHAR;
pos->attr = 0;
} else {
pos->data = (unicode_val_T)' ';
}
} else {
pos->data = data;
}
}
set_screen_dirty(term->screen, y, y);
}
#endif /* CONFIG_UTF_8 */
void
draw_text(struct terminal *term, int x, int y,
unsigned char *text, int length,
@ -288,6 +490,13 @@ draw_text(struct terminal *term, int x, int y,
assert(text && length >= 0);
if_assert_failed return;
#ifdef CONFIG_UTF_8
if (term->utf8) {
draw_text_utf8(term, x, y, text, length, attr, color);
return;
}
#endif /* CONFIG_UTF_8 */
if (length <= 0) return;
pos = get_char(term, x, y);
if (!pos) return;

View File

@ -1,6 +1,8 @@
#ifndef EL__TERMINAL_DRAW_H
#define EL__TERMINAL_DRAW_H
#include "intl/charsets.h" /* unicode_val_T */
struct color_pair;
struct box;
struct terminal;
@ -19,7 +21,11 @@ enum screen_char_attr {
/* One position in the terminal screen's image. */
struct screen_char {
/* Contains either character value or frame data. */
#ifdef CONFIG_UTF_8
unicode_val_T data;
#else
unsigned char data;
#endif /* CONFIG_UTF_8 */
/* Attributes are screen_char_attr bits. */
unsigned char attr;
@ -202,7 +208,11 @@ void draw_char_color(struct terminal *term, int x, int y,
struct color_pair *color);
/* Sets the data of a screen position. */
#ifdef CONFIG_UTF_8
void draw_char_data(struct terminal *term, int x, int y, unicode_val_T data);
#else
void draw_char_data(struct terminal *term, int x, int y, unsigned char data);
#endif /* CONFIG_UTF_8 */
/* Sets the data to @border and of a screen position. */
void draw_border_char(struct terminal *term, int x, int y,
@ -213,9 +223,15 @@ void draw_border_cross(struct terminal *, int x, int y,
enum border_cross_direction, struct color_pair *color);
/* Draws a char. */
#ifdef CONFIG_UTF_8
void draw_char(struct terminal *term, int x, int y,
unicode_val_T data, enum screen_char_attr attr,
struct color_pair *color);
#else
void draw_char(struct terminal *term, int x, int y,
unsigned char data, enum screen_char_attr attr,
struct color_pair *color);
#endif /* CONFIG_UTF_8 */
/* Draws area defined by @box using the same colors and attributes. */
void draw_box(struct terminal *term, struct box *box,
@ -230,6 +246,11 @@ void draw_shadow(struct terminal *term, struct box *box,
void draw_border(struct terminal *term, struct box *box,
struct color_pair *color, int width);
#ifdef CONFIG_UTF_8
void fix_dwchar_around_box(struct terminal *term, struct box *box, int border,
int shadow_width, int shadow_height);
#endif /* CONFIG_UTF_8 */
/* Draws @length chars from @text. */
void draw_text(struct terminal *term, int x, int y,
unsigned char *text, int length,

View File

@ -162,6 +162,12 @@ check_terminal_name(struct terminal *term, struct terminal_info *info)
object_unlock(term->spec);
term->spec = get_opt_rec(config_options, name);
object_lock(term->spec);
#ifdef CONFIG_UTF_8
/* Probably not best place for set this. But now we finally have
* term->spec and term->utf8 should be set before decode session info.
* --Scrool */
term->utf8 = get_opt_bool_tree(term->spec, "utf_8_io");
#endif /* CONFIG_UTF_8 */
}
#ifdef CONFIG_MOUSE
@ -259,9 +265,13 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
return 0;
}
if (interlink->utf_8.len) {
#ifdef CONFIG_UTF_8
utf8_io = !!term->utf8;
#else
utf8_io = get_opt_bool_tree(term->spec, "utf_8_io");
#endif /* CONFIG_UTF_8 */
if (interlink->utf_8.len) {
if ((key & 0xC0) == 0x80 && utf8_io) {
interlink->utf_8.ucs <<= 6;
interlink->utf_8.ucs |= key & 0x3F;
@ -280,11 +290,7 @@ handle_interlink_event(struct terminal *term, struct term_event *ev)
}
}
if (key < 0x80 || key > 0xFF
|| (utf8_io == -1
? !get_opt_bool_tree(term->spec, "utf_8_io")
: !utf8_io)) {
if (key < 0x80 || key > 0xFF || !utf8_io) {
term_send_event(term, ev);
break;

View File

@ -31,6 +31,7 @@
unsigned char frame_dumb[48] = " ||||++||++++++--|-+||++--|-+----++++++++ ";
static unsigned char frame_vt100[48] = "aaaxuuukkuxkjjjkmvwtqnttmlvwtqnvvwwmmllnnjla ";
#ifndef CONFIG_UTF_8
/* For UTF8 I/O */
static unsigned char frame_vt100_u[48] = {
177, 177, 177, 179, 180, 180, 180, 191,
@ -40,6 +41,7 @@ static unsigned char frame_vt100_u[48] = {
193, 194, 194, 192, 192, 218, 218, 197,
197, 217, 218, 177, 32, 32, 32, 32
};
#endif /* CONFIG_UTF_8 */
static unsigned char frame_freebsd[48] = {
130, 138, 128, 153, 150, 150, 150, 140,
@ -79,6 +81,13 @@ static struct string m11_hack_frame_seqs[] = {
/* begin border: */ TERM_STRING("\033[11m"),
};
#ifdef CONFIG_UTF_8
static struct string utf8_linux_frame_seqs[] = {
/* end border: */ TERM_STRING("\033[10m\033%G"),
/* begin border: */ TERM_STRING("\033%@\033[11m"),
};
#endif /* CONFIG_UTF_8 */
static struct string vt100_frame_seqs[] = {
/* end border: */ TERM_STRING("\x0f"),
/* begin border: */ TERM_STRING("\x0e"),
@ -100,10 +109,12 @@ struct screen_driver {
* uniquely identify the screen_driver. */
enum term_mode_type type;
#ifndef CONFIG_UTF_8
/* Charsets when doing UTF8 I/O. */
/* [0] is the common charset and [1] is the frame charset.
* Test wether to use UTF8 I/O using the use_utf8_io() macro. */
int charsets[2];
#endif /* CONFIG_UTF_8 */
/* The frame translation table. May be NULL. */
unsigned char *frame;
@ -120,6 +131,11 @@ struct screen_driver {
/* These are directly derived from the terminal options. */
unsigned int transparent:1;
#ifdef CONFIG_UTF_8
/* UTF-8 I/O */
unsigned int utf8:1;
#endif /* CONFIG_UTF_8 */
/* The terminal._template_ name. */
unsigned char name[1]; /* XXX: Keep last! */
};
@ -127,56 +143,81 @@ struct screen_driver {
static struct screen_driver dumb_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_DUMB,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ frame_dumb,
/* frame_seqs: */ NULL,
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
static struct screen_driver vt100_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_VT100,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ frame_vt100,
/* frame_seqs: */ vt100_frame_seqs,
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
static struct screen_driver linux_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_LINUX,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ NULL, /* No restrict_852 */
/* frame_seqs: */ NULL, /* No m11_hack */
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
static struct screen_driver koi8_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_KOI8,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ frame_koi,
/* frame_seqs: */ NULL,
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
static struct screen_driver freebsd_screen_driver = {
NULL_LIST_HEAD,
/* type: */ TERM_FREEBSD,
#ifndef CONFIG_UTF_8
/* charsets: */ { -1, -1 }, /* No UTF8 I/O */
#endif /* CONFIG_UTF_8 */
/* frame: */ frame_freebsd,
/* frame_seqs: */ NULL, /* No m11_hack */
/* underline: */ underline_seqs,
/* color_mode: */ COLOR_MODE_16,
/* transparent: */ 1,
#ifdef CONFIG_UTF_8
/* utf-8: */ 0,
#endif /* CONFIG_UTF_8 */
};
/* XXX: Keep in sync with enum term_mode_type. */
@ -188,13 +229,22 @@ static struct screen_driver *screen_drivers[] = {
/* TERM_FREEBSD: */ &freebsd_screen_driver,
};
#ifdef CONFIG_UTF_8
#define use_utf8_io(driver) ((driver)->utf8)
#else
#define use_utf8_io(driver) ((driver)->charsets[0] != -1)
#endif /* CONFIG_UTF_8 */
static INIT_LIST_HEAD(active_screen_drivers);
static void
update_screen_driver(struct screen_driver *driver, struct option *term_spec)
{
#ifdef CONFIG_UTF_8
driver->utf8 = get_opt_bool_tree(term_spec, "utf_8_io");
#else
int utf8_io = get_opt_bool_tree(term_spec, "utf_8_io");
#endif /* CONFIG_UTF_8 */
driver->color_mode = get_opt_int_tree(term_spec, "colors");
driver->transparent = get_opt_bool_tree(term_spec, "transparency");
@ -205,6 +255,25 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
driver->underline = NULL;
}
#ifdef CONFIG_UTF_8
if (driver->type == TERM_LINUX) {
if (get_opt_bool_tree(term_spec, "restrict_852"))
driver->frame = frame_restrict;
if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
if (driver->utf8)
driver->frame_seqs = utf8_linux_frame_seqs;
} else if (driver->type == TERM_FREEBSD) {
if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
} else if (driver->type == TERM_VT100) {
driver->frame = frame_vt100;
}
#else
if (utf8_io) {
driver->charsets[0] = get_opt_codepage_tree(term_spec, "charset");
if (driver->type == TERM_LINUX) {
@ -239,11 +308,11 @@ update_screen_driver(struct screen_driver *driver, struct option *term_spec)
} else if (driver->type == TERM_FREEBSD) {
if (get_opt_bool_tree(term_spec, "m11_hack"))
driver->frame_seqs = m11_hack_frame_seqs;
} else if (driver->type == TERM_VT100) {
driver->frame = frame_vt100;
}
}
#endif /* CONFIG_UTF_8 */
}
static int
@ -282,6 +351,10 @@ add_screen_driver(enum term_mode_type type, struct terminal *term, int env_len)
term->spec->change_hook = screen_driver_change_hook;
#ifdef CONFIG_UTF_8
term->utf8 = use_utf8_io(driver);
#endif /* CONFIG_UTF_8 */
return driver;
}
@ -300,6 +373,9 @@ get_screen_driver(struct terminal *term)
/* Some simple probably useless MRU ;) */
move_to_top_of_list(active_screen_drivers, driver);
#ifdef CONFIG_UTF_8
term->utf8 = use_utf8_io(driver);
#endif /* CONFIG_UTF_8 */
return driver;
}
@ -366,11 +442,15 @@ struct screen_state {
#define compare_bg_color(a, b) (TERM_COLOR_BACKGROUND(a) == TERM_COLOR_BACKGROUND(b))
#define compare_fg_color(a, b) (TERM_COLOR_FOREGROUND(a) == TERM_COLOR_FOREGROUND(b))
#define use_utf8_io(driver) ((driver)->charsets[0] != -1)
#ifdef CONFIG_UTF_8
static inline void
add_char_data(struct string *screen, struct screen_driver *driver,
unicode_val_T data, unsigned char border)
#else
static inline void
add_char_data(struct string *screen, struct screen_driver *driver,
unsigned char data, unsigned char border)
#endif /* CONFIG_UTF_8 */
{
if (!isscreensafe(data)) {
add_char_to_string(screen, ' ');
@ -381,13 +461,21 @@ add_char_data(struct string *screen, struct screen_driver *driver,
data = driver->frame[data - 176];
if (use_utf8_io(driver)) {
#ifdef CONFIG_UTF_8
if (border)
add_char_to_string(screen, (unsigned char)data);
else
if (data != UCS_NO_CHAR)
add_to_string(screen, encode_utf_8(data));
#else
int charset = driver->charsets[!!border];
add_to_string(screen, cp2utf_8(charset, data));
#endif /* CONFIG_UTF_8 */
return;
}
add_char_to_string(screen, data);
add_char_to_string(screen, (unsigned char)data);
}
/* Time critical section. */
@ -399,17 +487,32 @@ add_char16(struct string *screen, struct screen_driver *driver,
unsigned char underline = (ch->attr & SCREEN_ATTR_UNDERLINE);
unsigned char bold = (ch->attr & SCREEN_ATTR_BOLD);
if (border != state->border && driver->frame_seqs) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
border != state->border && driver->frame_seqs
) {
state->border = border;
add_term_string(screen, driver->frame_seqs[!!border]);
}
if (underline != state->underline && driver->underline) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
underline != state->underline && driver->underline
) {
state->underline = underline;
add_term_string(screen, driver->underline[!!underline]);
}
if (bold != state->bold) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
bold != state->bold
) {
state->bold = bold;
if (bold) {
add_bytes_to_string(screen, "\033[1m", 4);
@ -419,7 +522,12 @@ add_char16(struct string *screen, struct screen_driver *driver,
}
}
if (!compare_color(ch->color, state->color)) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
!compare_color(ch->color, state->color)
) {
copy_color(state->color, ch->color);
add_bytes_to_string(screen, "\033[0", 3);
@ -521,7 +629,12 @@ add_char256(struct string *screen, struct screen_driver *driver,
{
unsigned char attr_delta = (ch->attr ^ state->attr);
if (attr_delta) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
attr_delta
) {
if ((attr_delta & SCREEN_ATTR_FRAME) && driver->frame_seqs) {
state->border = !!(ch->attr & SCREEN_ATTR_FRAME);
add_term_string(screen, driver->frame_seqs[state->border]);
@ -544,7 +657,12 @@ add_char256(struct string *screen, struct screen_driver *driver,
state->attr = ch->attr;
}
if (!compare_color(ch->color, state->color)) {
if (
#ifdef CONFIG_UTF_8
(!use_utf8_io(driver) || ch->data != UCS_NO_CHAR) &&
#endif /* CONFIG_UTF_8 */
!compare_color(ch->color, state->color)
) {
copy_color(state->color, ch->color);
add_foreground_color(screen, color256_seqs, ch);

View File

@ -126,6 +126,11 @@ struct terminal {
* work and even maintaining these structures ;-). */
unsigned int master:1;
#ifdef CONFIG_UTF_8
/* Indicates whether UTF-8 I/O is used */
unsigned int utf8:1;
#endif /* CONFIG_UTF_8 */
/* The current tab number. */
int current_tab;

View File

@ -26,6 +26,7 @@
#include "document/options.h"
#include "document/renderer.h"
#include "document/view.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h"
#include "main/select.h"
#include "main/main.h"
@ -346,6 +347,11 @@ add_document_to_string(struct string *string, struct document *document)
assert(string && document);
if_assert_failed return NULL;
#ifdef CONFIG_UTF_8
if (is_cp_utf8(document->options.cp))
goto utf_8;
#endif /* CONFIG_UTF_8 */
for (y = 0; y < document->height; y++) {
int white = 0;
int x;
@ -378,7 +384,45 @@ add_document_to_string(struct string *string, struct document *document)
add_char_to_string(string, '\n');
}
#ifdef CONFIG_UTF_8
goto end;
utf_8:
for (y = 0; y < document->height; y++) {
struct screen_char *pos = document->data[y].chars;
int white = 0;
int x;
for (x = 0; x < document->data[y].length; x++) {
unicode_val_T data = pos->data;
unsigned int frame = (pos->attr & SCREEN_ATTR_FRAME);
if (!isscreensafe(data)) {
white++;
continue;
} else if (frame && data >= 176 && data < 224) {
data = frame_dumb[data - 176];
if (data <= ' ') {
/* Count spaces. */
white++;
} else {
/* Print spaces if any. */
if (white) {
add_xchar_to_string(string, ' ', white);
white = 0;
}
if (frame)
add_char_to_string(string, data);
else
add_to_string(string, encode_utf_8(data));
}
}
}
add_char_to_string(string, '\n');
}
end:
#endif /* CONFIG_UTF_8 */
return string;
}
@ -666,6 +710,11 @@ dump_to_file(struct document *document, int fd)
if (!buf) return -1;
#ifdef CONFIG_UTF_8
if (is_cp_utf8(document->options.cp))
goto utf_8;
#endif /* CONFIG_UTF_8 */
for (y = 0; y < document->height; y++) {
int white = 0;
int x;
@ -702,13 +751,64 @@ dump_to_file(struct document *document, int fd)
if (write_char('\n', fd, buf, &bptr))
goto fail;
}
#ifdef CONFIG_UTF_8
goto ref;
utf_8:
for (y = 0; y < document->height; y++) {
int white = 0;
int x;
for (x = 0; x < document->data[y].length; x++) {
unicode_val_T c;
unsigned char attr = document->data[y].chars[x].attr;
c = document->data[y].chars[x].data;
if ((attr & SCREEN_ATTR_FRAME)
&& c >= 176 && c < 224)
c = frame_dumb[c - 176];
else {
unsigned char *utf8_buf = encode_utf_8(c);
while (*utf8_buf) {
if (write_char(*utf8_buf++,
fd, buf, &bptr)) goto fail;
}
continue;
}
if (c <= ' ') {
/* Count spaces. */
white++;
continue;
}
/* Print spaces if any. */
while (white) {
if (write_char(' ', fd, buf, &bptr))
goto fail;
white--;
}
/* Print normal char. */
if (write_char(c, fd, buf, &bptr))
goto fail;
}
/* Print end of line. */
if (write_char('\n', fd, buf, &bptr))
goto fail;
}
#endif /* CONFIG_UTF_8 */
if (hard_write(fd, buf, bptr) != bptr) {
fail:
mem_free(buf);
return -1;
}
#ifdef CONFIG_UTF_8
ref:
#endif /* CONFIG_UTF_8 */
if (document->nlinks && get_opt_bool("document.dump.references")) {
int x;
unsigned char *header = "\nReferences\n\n Visible links\n";

View File

@ -163,11 +163,22 @@ init_form_state(struct form_control *fc, struct form_state *fs)
case FC_TEXTAREA:
fs->value = stracpy(fc->default_value);
fs->state = strlen(fc->default_value);
#ifdef CONFIG_UTF_8
if (fc->type == FC_TEXT)
fs->state_cell = utf8_ptr2cells(fs->value, NULL);
if (fc->type == FC_PASSWORD)
fs->state_cell = utf8_ptr2chars(fs->value, NULL);
if (fc->type == FC_TEXTAREA)
fs->state_cell = 0;
#endif /* CONFIG_UTF_8 */
fs->vpos = 0;
break;
case FC_FILE:
fs->value = stracpy("");
fs->state = 0;
#ifdef CONFIG_UTF_8
fs->state_cell = 0;
#endif /* CONFIG_UTF_8 */
fs->vpos = 0;
break;
case FC_SELECT:
@ -330,21 +341,27 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
dy = box->y - vs->y;
switch (fc->type) {
unsigned char *s;
#ifdef CONFIG_UTF_8
unsigned char *text, *end;
#endif /* CONFIG_UTF_8 */
int len;
int i, x, y;
case FC_TEXT:
case FC_PASSWORD:
case FC_FILE:
int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state);
if (!link->npoints) break;
y = link->points[0].y + dy;
if (!row_is_in_box(box, y))
break;
len = strlen(fs->value) - fs->vpos;
x = link->points[0].x + dx;
#ifdef CONFIG_UTF_8
if (term->utf8) goto utf_8;
#endif /* CONFIG_UTF_8 */
int_bounds(&fs->vpos, fs->state - fc->size + 1, fs->state);
len = strlen(fs->value) - fs->vpos;
for (i = 0; i < fc->size; i++, x++) {
unsigned char data;
@ -360,6 +377,43 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
draw_char_data(term, x, y, data);
}
break;
#ifdef CONFIG_UTF_8
utf_8:
end = NULL; /* Shut up the compiler. */
int_bounds(&fs->vpos, fs->state_cell - fc->size + 1, fs->state_cell);
if (fc->type == FC_PASSWORD)
len = utf8_ptr2chars(fs->value + fs->vpos, NULL);
else
len = utf8_ptr2cells(fs->value + fs->vpos, NULL);
text = fs->value;
end = strchr(text, '\0');
for (i = 0; i < fc->size; i++, x++) {
unicode_val_T data;
if (!col_is_in_box(box, x)) continue;
if (fs->value && i >= -fs->vpos && i < len) {
if (fc->type != FC_PASSWORD)
data = utf_8_to_unicode(&text, end);
else
data = '*';
} else
data = '_';
if (unicode_to_cell(data) == 2) {
if (i + 1 < fc->size) {
draw_char_data(term, x++, y, data);
data = UCS_NO_CHAR;
i++;
} else
data = ' ';
}
draw_char_data(term, x, y, data);
}
break;
#endif /* CONFIG_UTF_8 */
case FC_TEXTAREA:
draw_textarea(term, fs, doc_view, link);
break;
@ -378,6 +432,9 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
else
/* XXX: when can this happen? --pasky */
s = "";
#ifdef CONFIG_UTF_8
if (term->utf8) goto utf_8_select;
#endif /* CONFIG_UTF_8 */
len = s ? strlen(s) : 0;
for (i = 0; i < link->npoints; i++) {
x = link->points[i].x + dx;
@ -386,6 +443,36 @@ draw_form_entry(struct terminal *term, struct document_view *doc_view,
draw_char_data(term, x, y, i < len ? s[i] : '_');
}
break;
#ifdef CONFIG_UTF_8
utf_8_select:
text = s;
end = strchr(s, '\0');
len = utf8_ptr2cells(text, end);
for (i = 0; i < link->npoints; i++) {
x = link->points[i].x + dx;
y = link->points[i].y + dy;
if (is_in_box(box, x, y)) {
unicode_val_T data;
if (i < len) {
int cell;
data = utf_8_to_unicode(&s, end);
cell = unicode_to_cell(data);
if (i + 1 < len && cell == 2) {
draw_char_data(term, x++, y, data);
data = UCS_NO_CHAR;
i++;
} else if (cell == 2) {
data = ' ';
}
} else
data = '_';
draw_char_data(term, x, y, data);
}
}
break;
#endif /* CONFIG_UTF_8 */
case FC_SUBMIT:
case FC_IMAGE:
case FC_RESET:
@ -1195,6 +1282,9 @@ field_op(struct session *ses, struct document_view *doc_view,
unsigned char *text;
int length;
enum frame_event_status status = FRAME_EVENT_REFRESH;
#ifdef CONFIG_UTF_8
int utf8 = ses->tab->term->utf8;
#endif /* CONFIG_UTF_8 */
assert(ses && doc_view && link && ev);
if_assert_failed return FRAME_EVENT_OK;
@ -1214,49 +1304,140 @@ field_op(struct session *ses, struct document_view *doc_view,
switch (action_id) {
case ACT_EDIT_LEFT:
#ifdef CONFIG_UTF_8
if (fc->type == FC_TEXTAREA) {
status = textarea_op_left(fs, fc, utf8);
break;
}
if (utf8) {
int old_state = fs->state;
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state = new_value - fs->value;
if (old_state != fs->state) {
if (fc->type == FC_PASSWORD)
fs->state_cell = int_max(fs->state_cell - 1, 0);
else
fs->state_cell = int_max(utf8_char2cells(new_value, NULL) - 1, 0);
}
} else
#endif /* CONFIG_UTF_8 */
fs->state = int_max(fs->state - 1, 0);
break;
case ACT_EDIT_RIGHT:
#ifdef CONFIG_UTF_8
if (fc->type == FC_TEXTAREA) {
status = textarea_op_right(fs, fc, utf8);
break;
}
if (utf8) {
unsigned char *text = fs->value + fs->state;
unsigned char *end = strchr(text, '\0');
int old_state = fs->state;
unicode_val_T data = utf_8_to_unicode(&text, end);
fs->state = (int)(text - fs->value);
if (old_state != fs->state) {
if (fc->type == FC_PASSWORD)
fs->state_cell = int_min(fs->state_cell + 1,
utf8_ptr2cells(fs->value, NULL));
else
fs->state_cell += unicode_to_cell(data);
}
} else
#endif /* CONFIG_UTF_8 */
fs->state = int_min(fs->state + 1, strlen(fs->value));
break;
case ACT_EDIT_HOME:
#ifdef CONFIG_UTF_8
if (fc->type == FC_TEXTAREA) {
status = textarea_op_home(fs, fc, utf8);
} else {
fs->state = 0;
fs->state_cell = 0;
}
#else
if (fc->type == FC_TEXTAREA) {
status = textarea_op_home(fs, fc);
} else {
fs->state = 0;
}
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_UP:
if (fc->type != FC_TEXTAREA)
status = FRAME_EVENT_IGNORED;
else
#ifdef CONFIG_UTF_8
status = textarea_op_up(fs, fc, utf8);
#else
status = textarea_op_up(fs, fc);
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_DOWN:
if (fc->type != FC_TEXTAREA)
status = FRAME_EVENT_IGNORED;
else
#ifdef CONFIG_UTF_8
status = textarea_op_down(fs, fc, utf8);
#else
status = textarea_op_down(fs, fc);
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_END:
if (fc->type == FC_TEXTAREA) {
#ifdef CONFIG_UTF_8
status = textarea_op_end(fs, fc, utf8);
#else
status = textarea_op_end(fs, fc);
#endif /* CONFIG_UTF_8 */
} else {
fs->state = strlen(fs->value);
#ifdef CONFIG_UTF_8
if (utf8 && fc->type != FC_PASSWORD)
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
else if(utf8)
fs->state_cell = utf8_ptr2chars(fs->value,
fs->value + fs->state);
#endif /* CONFIG_UTF_8 */
}
break;
case ACT_EDIT_BEGINNING_OF_BUFFER:
if (fc->type == FC_TEXTAREA) {
#ifdef CONFIG_UTF_8
status = textarea_op_bob(fs, fc, utf8);
#else
status = textarea_op_bob(fs, fc);
#endif /* CONFIG_UTF_8 */
} else {
fs->state = 0;
}
#ifdef CONFIG_UTF_8
fs->state_cell = 0;
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_END_OF_BUFFER:
if (fc->type == FC_TEXTAREA) {
#ifdef CONFIG_UTF_8
status = textarea_op_eob(fs, fc, utf8);
#else
status = textarea_op_eob(fs, fc);
#endif /* CONFIG_UTF_8 */
} else {
fs->state = strlen(fs->value);
#ifdef CONFIG_UTF_8
if (utf8 && fc->type != FC_PASSWORD)
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
else if(utf8)
fs->state_cell = utf8_ptr2chars(fs->value,
fs->value + fs->state);
#endif /* CONFIG_UTF_8 */
}
break;
case ACT_EDIT_OPEN_EXTERNAL:
@ -1274,6 +1455,9 @@ field_op(struct session *ses, struct document_view *doc_view,
if (!form_field_is_readonly(fc))
fs->value[0] = 0;
fs->state = 0;
#ifdef CONFIG_UTF_8
fs->state_cell = 0;
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_PASTE_CLIPBOARD:
if (form_field_is_readonly(fc)) break;
@ -1289,13 +1473,27 @@ field_op(struct session *ses, struct document_view *doc_view,
fs->value = v;
memmove(v, text, length + 1);
fs->state = strlen(fs->value);
#ifdef CONFIG_UTF_8
if(utf8 && fc->type == FC_PASSWORD)
fs->state_cell = utf8_ptr2chars(fs->value,
fs->value + fs->state);
else if (utf8 && fc->type == FC_TEXTAREA)
fs->state_cell = 0;
else if (utf8)
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
#endif /* CONFIG_UTF_8 */
}
}
mem_free(text);
break;
case ACT_EDIT_ENTER:
if (fc->type == FC_TEXTAREA) {
#ifdef CONFIG_UTF_8
status = textarea_op_enter(fs, fc, utf8);
#else
status = textarea_op_enter(fs, fc);
#endif /* CONFIG_UTF_8 */
break;
}
@ -1320,12 +1518,33 @@ field_op(struct session *ses, struct document_view *doc_view,
status = FRAME_EVENT_OK;
break;
}
#ifdef CONFIG_UTF_8
if (utf8) {
int old_state = fs->state;
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state = new_value - fs->value;
if (old_state != fs->state) {
if (fc->type == FC_TEXTAREA)
fs->state_cell = 0;
else if (fc->type == FC_PASSWORD)
fs->state_cell = int_max(fs->state_cell - 1, 0);
else
fs->state_cell -= utf8_char2cells(new_value, NULL);
length = strlen(fs->value + old_state) + 1;
memmove(new_value, fs->value + old_state, length);
}
} else
#endif /* CONFIG_UTF_8 */
{
length = strlen(fs->value + fs->state) + 1;
text = fs->value + fs->state;
memmove(text - 1, text, length);
fs->state--;
}
break;
case ACT_EDIT_DELETE:
if (form_field_is_readonly(fc)) {
@ -1338,7 +1557,20 @@ field_op(struct session *ses, struct document_view *doc_view,
status = FRAME_EVENT_OK;
break;
}
#ifdef CONFIG_UTF_8
if (utf8) {
unsigned char *end = fs->value + length;
unsigned char *text = fs->value + fs->state;
unsigned char *old = text;
utf_8_to_unicode(&text, end);
if (old != text) {
memmove(old, text,
(int)(end - text) + 1);
}
break;
}
#endif /* CONFIG_UTF_8 */
text = fs->value + fs->state;
memmove(text, text + 1, length - fs->state);
@ -1368,6 +1600,18 @@ field_op(struct session *ses, struct document_view *doc_view,
memmove(text, fs->value + fs->state, length);
fs->state = (int) (text - fs->value);
#ifdef CONFIG_UTF_8
if (utf8) {
if(fc->type == FC_PASSWORD)
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
else if (fc->type == FC_TEXTAREA)
fs->state_cell = 0;
else
fs->state_cell = utf8_ptr2cells(fs->value,
fs->value + fs->state);
}
#endif /* CONFIG_UTF_8 */
break;
case ACT_EDIT_KILL_TO_EOL:
if (form_field_is_readonly(fc)) {
@ -1467,12 +1711,54 @@ field_op(struct session *ses, struct document_view *doc_view,
if (form_field_is_readonly(fc)
|| strlen(fs->value) >= fc->maxlength
|| !insert_in_string(&fs->value, fs->state, "?", 1)) {
#ifndef CONFIG_UTF_8
|| !insert_in_string(&fs->value, fs->state, "?", 1)
#endif /* CONFIG_UTF_8 */
)
{
status = FRAME_EVENT_OK;
break;
}
#ifdef CONFIG_UTF_8
if (utf8) {
static unsigned char buf[7];
static int i = 0;
unicode_val_T data;
unsigned char *t;
t = buf;
buf[i++] = get_kbd_key(ev);
buf[i] = 0;
data = utf_8_to_unicode(&t, buf + i);
if (data != UCS_NO_CHAR) {
if (!insert_in_string(&fs->value, fs->state, buf, i)) {
i = 0;
return FRAME_EVENT_OK;
}
fs->state += i;
if (fc->type == FC_PASSWORD)
fs->state_cell++;
else if (fc->type == FC_TEXTAREA)
fs->state_cell = 0;
else
fs->state_cell += unicode_to_cell(data);
i = 0;
break;
}
if (i == 6) {
i = 0;
}
return FRAME_EVENT_OK;
} else {
if (!insert_in_string(&fs->value, fs->state, "?", 1))
return FRAME_EVENT_OK;
fs->value[fs->state++] = get_kbd_key(ev);
}
#else
fs->value[fs->state++] = get_kbd_key(ev);
#endif /* CONFIG_UTF_8 */
break;
}

View File

@ -39,6 +39,9 @@ struct form_state {
unsigned char *value;
int state;
#ifdef CONFIG_UTF_8
int state_cell;
#endif /* CONFIG_UTF_8 */
int vpos;
int vypos;

View File

@ -114,6 +114,9 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
{
struct form_control *fc;
struct form_state *fs;
#ifdef CONFIG_UTF_8
int utf8 = doc_view->document->options.utf8;
#endif /* CONFIG_UTF_8 */
switch (link->type) {
case LINK_CHECKBOX:
@ -125,12 +128,21 @@ get_link_cursor_offset(struct document_view *doc_view, struct link *link)
case LINK_FIELD:
fc = get_link_form_control(link);
fs = find_form_state(doc_view, fc);
#ifdef CONFIG_UTF_8
if (utf8) {
return fs ? fs->state_cell - fs->vpos : 0;
} else
#endif /* CONFIG_UTF_8 */
return fs ? fs->state - fs->vpos : 0;
case LINK_AREA:
fc = get_link_form_control(link);
fs = find_form_state(doc_view, fc);
#ifdef CONFIG_UTF_8
return fs ? area_cursor(fc, fs, utf8) : 0;
#else
return fs ? area_cursor(fc, fs) : 0;
#endif /* CONFIG_UTF_8 */
case LINK_HYPERTEXT:
case LINK_MAP:
@ -1342,7 +1354,7 @@ end:
do_menu(term, mi, ses, 1);
}
/* Return current link's title. Pretty trivial. */
/* Return current link's title. */
unsigned char *
get_current_link_title(struct document_view *doc_view)
{
@ -1356,7 +1368,29 @@ get_current_link_title(struct document_view *doc_view)
link = get_current_link(doc_view);
return (link && link->title && *link->title) ? stracpy(link->title) : NULL;
if (link && link->title && *link->title) {
unsigned char *link_title, *src;
struct conv_table *convert_table;
convert_table = get_translation_table(doc_view->document->cp,
doc_view->document->options.cp);
link_title = convert_string(convert_table, link->title,
strlen(link->title),
doc_view->document->options.cp,
CSM_DEFAULT, NULL, NULL, NULL);
/* Remove illicit chars. */
#ifdef CONFIG_UTF_8
if (link_title && !doc_view->document->options.utf8)
#endif /* CONFIG_UTF_8 */
for (src = link_title; *src; src++)
if (!isprint(*src) || iscntrl(*src))
*src = '*';
return link_title;
}
return NULL;
}
unsigned char *
@ -1401,6 +1435,11 @@ get_current_link_info(struct session *ses, struct document_view *doc_view)
add_char_to_string(&str, ')');
}
#ifdef CONFIG_UTF_8
if (term->utf8)
decode_uri_string(&str);
else
#endif /* CONFIG_UTF_8 */
decode_uri_string_for_display(&str);
return str.source;
}

View File

@ -11,6 +11,7 @@ struct session;
struct term_event;
struct terminal;
struct uri;
struct conv_table;
void set_link(struct document_view *doc_view);
void clear_link(struct terminal *term, struct document_view *doc_view);

View File

@ -9,6 +9,11 @@
#endif
#include <ctype.h> /* tolower(), isprint() */
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
#include <wctype.h>
#endif
#include <sys/types.h> /* FreeBSD needs this before regex.h */
#ifdef HAVE_REGEX_H
#include <regex.h>
@ -22,6 +27,7 @@
#include "config/kbdbind.h"
#include "document/document.h"
#include "document/view.h"
#include "intl/charsets.h"
#include "intl/gettext/libintl.h"
#include "main/event.h"
#include "main/module.h"
@ -44,9 +50,15 @@
static INIT_INPUT_HISTORY(search_history);
#undef UCHAR
#ifdef CONFIG_UTF_8
#define UCHAR unicode_val_T
#else
#define UCHAR unsigned char
#endif
static inline void
add_srch_chr(struct document *document, unsigned char c, int x, int y, int nn)
add_srch_chr(struct document *document, UCHAR c, int x, int y, int nn)
{
assert(document);
if_assert_failed return;
@ -146,7 +158,7 @@ get_srch(struct document *document)
x++);
for (; x < width; x++) {
unsigned char c = document->data[y].chars[x].data;
UCHAR c = document->data[y].chars[x].data;
int count = 0;
int xx;
@ -441,18 +453,58 @@ is_in_range_regex(struct document *document, int y, int height,
}
#endif /* HAVE_REGEX_H */
/* Returns an allocated string which is a lowered copy of passed one. */
static unsigned char *
lowered_string(unsigned char *text, int textlen)
static UCHAR *
memacpy_u(unsigned char *text, int textlen, int utf8)
{
unsigned char *ret;
#ifdef CONFIG_UTF_8
UCHAR *mem = mem_alloc((textlen + 1) * sizeof(UCHAR));
if (textlen < 0) textlen = strlen(text);
if (!mem) return NULL;
if (utf8) {
int i;
ret = mem_calloc(1, textlen + 1);
for (i = 0; i < textlen; i++)
mem[i] = utf_8_to_unicode(&text, text + 7);
} else {
int i;
for (i = 0; i < textlen; i++)
mem[i] = text[i];
}
mem[textlen] = 0;
return mem;
#else
return memacpy(text, textlen);
#endif
}
static int
strlen_u(unsigned char *text, int utf8)
{
#ifdef CONFIG_UTF_8
if (utf8)
return strlen_utf8(&text);
#endif
return strlen(text);
}
/* Returns an allocated string which is a lowered copy of passed one. */
static UCHAR *
lowered_string(unsigned char *text, int textlen, int utf8)
{
UCHAR *ret;
if (textlen < 0) textlen = strlen_u(text, utf8);
ret = memacpy_u(text, textlen, utf8);
if (ret && textlen) {
do {
ret[textlen] = tolower(text[textlen]);
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
ret[textlen] = utf8 ? towlower(ret[textlen]) : tolower(ret[textlen]);
#else
ret[textlen] = tolower(ret[textlen]);
#endif
} while (textlen--);
}
@ -463,14 +515,14 @@ static int
is_in_range_plain(struct document *document, int y, int height,
unsigned char *text, int textlen,
int *min, int *max,
struct search *s1, struct search *s2)
struct search *s1, struct search *s2, int utf8)
{
int yy = y + height;
unsigned char *txt;
UCHAR *txt;
int found = 0;
int case_sensitive = get_opt_bool("document.browse.search.case");
txt = case_sensitive ? stracpy(text) : lowered_string(text, textlen);
txt = case_sensitive ? memacpy_u(text, textlen, utf8) : lowered_string(text, textlen, utf8);
if (!txt) return -1;
/* TODO: This is a great candidate for nice optimizations. Fresh CS
@ -478,9 +530,11 @@ is_in_range_plain(struct document *document, int y, int height,
* trivial, probably a starter; very fast as well) or Turbo-BM (or
* maybe some other Boyer-Moore variant, I don't feel that strong in
* this area), hmm? >:) --pasky */
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
#define maybe_tolower(c) (case_sensitive ? (c) : utf8 ? towlower(c) : tolower(c))
#else
#define maybe_tolower(c) (case_sensitive ? (c) : tolower(c))
#endif
for (; s1 <= s2; s1++) {
int i;
@ -513,18 +567,23 @@ srch_failed:
return found;
}
static int
is_in_range(struct document *document, int y, int height,
unsigned char *text, int *min, int *max)
{
struct search *s1, *s2;
int textlen;
int utf8 = 0;
assert(document && text && min && max);
if_assert_failed return -1;
#ifdef CONFIG_UTF_8
utf8 = document->options.utf8;
#endif
*min = INT_MAX, *max = 0;
textlen = strlen(text);
textlen = strlen_u(text, utf8);
if (get_range(document, y, height, textlen, &s1, &s2))
return 0;
@ -535,7 +594,7 @@ is_in_range(struct document *document, int y, int height,
min, max, s1, s2);
#endif
return is_in_range_plain(document, y, height, text, textlen,
min, max, s1, s2);
min, max, s1, s2, utf8);
}
#define realloc_points(pts, size) \
@ -543,24 +602,28 @@ is_in_range(struct document *document, int y, int height,
static void
get_searched_plain(struct document_view *doc_view, struct point **pt, int *pl,
int l, struct search *s1, struct search *s2)
int l, struct search *s1, struct search *s2, int utf8)
{
unsigned char *txt;
UCHAR *txt;
struct point *points = NULL;
struct box *box;
int xoffset, yoffset;
int len = 0;
int case_sensitive = get_opt_bool("document.browse.search.case");
txt = case_sensitive ? stracpy(*doc_view->search_word)
: lowered_string(*doc_view->search_word, l);
txt = case_sensitive ? memacpy_u(*doc_view->search_word, l, utf8)
: lowered_string(*doc_view->search_word, l, utf8);
if (!txt) return;
box = &doc_view->box;
xoffset = box->x - doc_view->vs->x;
yoffset = box->y - doc_view->vs->y;
#if defined(CONFIG_UTF_8) && defined(HAVE_WCTYPE_H)
#define maybe_tolower(c) (case_sensitive ? (c) : utf8 ? towlower(c) : tolower(c))
#else
#define maybe_tolower(c) (case_sensitive ? (c) : tolower(c))
#endif
for (; s1 <= s2; s1++) {
int i;
@ -671,7 +734,7 @@ get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
#endif /* HAVE_REGEX_H */
static void
get_searched(struct document_view *doc_view, struct point **pt, int *pl)
get_searched(struct document_view *doc_view, struct point **pt, int *pl, int utf8)
{
struct search *s1, *s2;
int l;
@ -683,7 +746,7 @@ get_searched(struct document_view *doc_view, struct point **pt, int *pl)
return;
get_search_data(doc_view->document);
l = strlen(*doc_view->search_word);
l = strlen_u(*doc_view->search_word, utf8);
if (get_range(doc_view->document, doc_view->vs->y,
doc_view->box.height, l, &s1, &s2)) {
*pt = NULL;
@ -697,7 +760,7 @@ get_searched(struct document_view *doc_view, struct point **pt, int *pl)
get_searched_regex(doc_view, pt, pl, l, s1, s2);
else
#endif
get_searched_plain(doc_view, pt, pl, l, s1, s2);
get_searched_plain(doc_view, pt, pl, l, s1, s2, utf8);
}
/* Highlighting of searched strings. */
@ -706,6 +769,7 @@ draw_searched(struct terminal *term, struct document_view *doc_view)
{
struct point *pt = NULL;
int len = 0;
int utf8 = 0;
assert(term && doc_view);
if_assert_failed return;
@ -713,7 +777,10 @@ draw_searched(struct terminal *term, struct document_view *doc_view)
if (!has_search_word(doc_view))
return;
get_searched(doc_view, &pt, &len);
#ifdef CONFIG_UTF_8
utf8 = doc_view->document->options.utf8;
#endif
get_searched(doc_view, &pt, &len, utf8);
if (len) {
int i;
struct color_pair *color = get_bfu_color(term, "searched");
@ -856,6 +923,11 @@ point_intersect(struct point *p1, int l1, struct point *p2, int l2)
static int
find_next_link_in_search(struct document_view *doc_view, int direction)
{
int utf8 = 0;
#ifdef CONFIG_UTF_8
utf8 = doc_view->document->options.utf8;
#endif
assert(doc_view && doc_view->vs);
if_assert_failed return 0;
@ -879,7 +951,7 @@ find_next_link_in_search(struct document_view *doc_view, int direction)
nt:
link = &doc_view->document->links[doc_view->vs->current_link];
get_searched(doc_view, &pt, &len);
get_searched(doc_view, &pt, &len, utf8);
if (point_intersect(pt, len, link->points, link->npoints)) {
mem_free(pt);
return 0;
@ -1174,7 +1246,7 @@ fixup_typeahead_match(struct session *ses, struct document_view *doc_view)
doc_view->box.height += 1;
}
static inline unsigned char
static inline UCHAR
get_document_char(struct document *document, int x, int y)
{
return (document->height > y && document->data[y].length > x)
@ -1196,7 +1268,7 @@ draw_typeahead_match(struct terminal *term, struct document_view *doc_view,
for (i = 0, j = 0; text[j] && i < end; i++, j++) {
int x = link->points[i].x;
int y = link->points[i].y;
unsigned char data = get_document_char(doc_view->document, x, y);
UCHAR data = get_document_char(doc_view->document, x, y);
/* Text wrapping might remove space chars from the link
* position array so try to align the matched typeahead text
@ -1311,7 +1383,6 @@ text_typeahead_handler(struct input_line *line, int action_id)
* clears the last search. */
search_for_do(ses, buffer, direction, 0);
}
goto_current_link(ses, doc_view, 0);
return INPUT_LINE_CANCEL;
case ACT_EDIT_PREVIOUS_ITEM:

View File

@ -40,6 +40,11 @@
struct line_info {
int start;
int end;
#ifdef CONFIG_UTF_8
int last_char_width;
int split_prev:1;
int split_next:1;
#endif /* CONFIG_UTF_8 */
};
/* We add two extra entries to the table so the ending info can be added
@ -47,6 +52,90 @@ struct line_info {
#define realloc_line_info(info, size) \
mem_align_alloc(info, size, (size) + 3, 0xFF)
#ifdef CONFIG_UTF_8
/* Allocates a line_info table describing the layout of the textarea buffer.
*
* @width is max width and the offset at which text will be wrapped
* @wrap controls how the wrapping of text is performed
* @format is non zero the @text will be modified to make it suitable for
* encoding it for form posting
*/
static struct line_info *
format_textutf8(unsigned char *text, int width, enum form_wrap wrap, int format)
{
struct line_info *line = NULL;
int line_number = 0;
int begin = 0;
int pos = 0;
int skip;
unsigned char *wrappos=NULL;
int chars_cells=0; /* Number of console chars on line */
assert(text);
if_assert_failed return NULL;
/* Allocate the ending entries */
if (!realloc_line_info(&line, 0))
return NULL;
while (text[pos]) {
int char_cells = utf8_char2cells(&text[pos], NULL);
if (text[pos] == ' ')
wrappos = &text[pos];
if (text[pos] == '\n') {
skip = 1;
} else if (wrap == FORM_WRAP_NONE || chars_cells + char_cells < width) {
pos += utf8charlen(&text[pos]);
chars_cells += char_cells;
continue;
} else {
if (wrappos) {
/* When formatting text for form submitting we
* have to apply the wrapping mode. */
if (wrap == FORM_WRAP_HARD && format)
*wrappos = '\n';
pos = wrappos - text;
}
skip = !!wrappos;
}
if (!realloc_line_info(&line, line_number)) {
mem_free_if(line);
return NULL;
}
line[line_number].last_char_width = char_cells;
line[line_number].split_next = !skip;
line[line_number].start = begin;
line[line_number++].end = pos;
line[line_number].split_prev = !skip;
begin = pos += skip;
chars_cells = 0;
wrappos = NULL;
}
line[line_number].split_next = 0;
/* Flush the last text before the loop ended */
line[line_number].start = begin;
line[line_number++].end = pos;
/* Add end marker */
line[line_number].start = line[line_number].end = -1;
line[line_number].split_next = line[line_number].split_prev = 0;
line[0].split_prev = 0;
return line;
}
#endif /* CONFIG_UTF_8 */
/* Allocates a line_info table describing the layout of the textarea buffer.
*
* @width is max width and the offset at which text will be wrapped
@ -137,6 +226,59 @@ get_textarea_line_number(struct line_info *line, int cursor_position)
/* Fixes up the vpos and vypos members of the form_state. Returns the
* logical position in the textarea view. */
#ifdef CONFIG_UTF_8
int
area_cursor(struct form_control *fc, struct form_state *fs, int utf8)
{
struct line_info *line;
int x, y;
assert(fc && fs);
if_assert_failed return 0;
if (utf8)
line = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
else
line = format_text(fs->value, fc->cols, fc->wrap, 0);
if (!line) return 0;
if (fs->state_cell)
y = get_textarea_line_number(line, fs->state_cell);
else
y = get_textarea_line_number(line, fs->state);
if (y == -1) {
mem_free(line);
return 0;
}
if (utf8) {
if (fs->state_cell) {
x = utf8_ptr2cells(fs->value + line[y].start,
fs->value + fs->state_cell);
x += line[y].last_char_width;
} else
x = utf8_ptr2cells(fs->value + line[y].start,
fs->value + fs->state);
} else {
x = fs->state - line[y].start;
if (fc->wrap && x == fc->cols) x--;
}
mem_free(line);
int_bounds(&fs->vpos, x - fc->cols + 1, x);
int_bounds(&fs->vypos, y - fc->rows + 1, y);
x -= fs->vpos;
y -= fs->vypos;
return y * fc->cols + x;
}
#else
int
area_cursor(struct form_control *fc, struct form_state *fs)
{
@ -169,6 +311,91 @@ area_cursor(struct form_control *fc, struct form_state *fs)
return y * fc->cols + x;
}
#endif
#ifdef CONFIG_UTF_8
static void
draw_textarea_utf8(struct terminal *term, struct form_state *fs,
struct document_view *doc_view, struct link *link)
{
struct line_info *line, *linex;
struct form_control *fc;
struct box *box;
int vx, vy;
int sl, ye;
int x, xbase, y;
assert(term && doc_view && doc_view->document && doc_view->vs && link);
if_assert_failed return;
fc = get_link_form_control(link);
assertm(fc, "link %d has no form control", (int) (link - doc_view->document->links));
if_assert_failed return;
box = &doc_view->box;
vx = doc_view->vs->x;
vy = doc_view->vs->y;
if (!link->npoints) return;
area_cursor(fc, fs, 1);
linex = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
if (!linex) return;
line = linex;
sl = fs->vypos;
while (line->start != -1 && sl) sl--, line++;
xbase = link->points[0].x + box->x - vx;
y = link->points[0].y + box->y - vy;
ye = y + fc->rows;
for (; line->start != -1 && y < ye; line++, y++) {
int i;
unsigned char *text, *end;
text = fs->value + line->start;
end = fs->value + line->end;
text += utf8_cells2bytes(text, fs->vpos, end);
if (!row_is_in_box(box, y)) continue;
for (i = 0, x = xbase; i < fc->cols; i++, x++) {
unicode_val_T data;
if (!col_is_in_box(box, x))
continue;
if (i >= -fs->vpos && text < end) {
int cell;
data = utf_8_to_unicode(&text, end);
cell = unicode_to_cell(data);
if (cell == 2) {
draw_char_data(term, x++, y, data);
i++;
data = UCS_NO_CHAR;
}
} else
data = '_';
draw_char_data(term, x, y, data);
}
}
for (; y < ye; y++) {
int i;
if (!row_is_in_box(box, y)) continue;
for (i = 0, x = xbase; i < fc->cols; i++, x++) {
if (col_is_in_box(box, x))
draw_char_data(term, x, y, '_');
}
}
mem_free(linex);
}
#endif /* CONFIG_UTF_8 */
void
draw_textarea(struct terminal *term, struct form_state *fs,
@ -183,6 +410,13 @@ draw_textarea(struct terminal *term, struct form_state *fs,
assert(term && doc_view && doc_view->document && doc_view->vs && link);
if_assert_failed return;
#ifdef CONFIG_UTF_8
if (term->utf8) {
draw_textarea_utf8(term, fs, doc_view, link);
return;
}
#endif /* CONFIG_UTF_8 */
fc = get_link_form_control(link);
assertm(fc, "link %d has no form control", (int) (link - doc_view->document->links));
if_assert_failed return;
@ -192,7 +426,11 @@ draw_textarea(struct terminal *term, struct form_state *fs,
vy = doc_view->vs->y;
if (!link->npoints) return;
#ifdef CONFIG_UTF_8
area_cursor(fc, fs, 0);
#else
area_cursor(fc, fs);
#endif /* CONFIG_UTF_8 */
linex = format_text(fs->value, fc->cols, fc->wrap, 0);
if (!linex) return;
line = linex;
@ -257,6 +495,7 @@ encode_textarea(struct submitted_value *sv)
/* We need to reformat text now if it has to be wrapped hard, just
* before encoding it. */
/* TODO: Do we need here UTF-8 format or not? --scrool */
blabla = format_text(sv->value, fc->cols, fc->wrap, 1);
mem_free_if(blabla);
@ -447,6 +686,39 @@ menu_textarea_edit(struct terminal *term, void *xxx, void *ses_)
textarea_edit(0, term, fs, doc_view, link);
}
#ifdef CONFIG_UTF_8
static enum frame_event_status
textarea_op(struct form_state *fs, struct form_control *fc, int utf8,
int (*do_op)(struct form_state *, struct line_info *, int, int))
{
struct line_info *line;
int current, state;
int state_cell;
assert(fs && fs->value && fc);
if_assert_failed return FRAME_EVENT_OK;
if (utf8)
line = format_textutf8(fs->value, fc->cols, fc->wrap, 0);
else
line = format_text(fs->value, fc->cols, fc->wrap, 0);
if (!line) return FRAME_EVENT_OK;
current = get_textarea_line_number(line, fs->state);
state = fs->state;
state_cell = fs->state_cell;
if (do_op(fs, line, current, utf8)) {
mem_free(line);
return FRAME_EVENT_IGNORED;
}
mem_free(line);
return (fs->state == state && fs->state_cell == state_cell)
? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
}
#else
static enum frame_event_status
textarea_op(struct form_state *fs, struct form_control *fc,
int (*do_op)(struct form_state *, struct line_info *, int))
@ -471,14 +743,88 @@ textarea_op(struct form_state *fs, struct form_control *fc,
return fs->state == state ? FRAME_EVENT_OK : FRAME_EVENT_REFRESH;
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
void
new_pos(struct form_state *fs, struct line_info *line, int current, int max_cells)
{
unsigned char *text = fs->value + line[current].start;
unsigned char *end = fs->value + line[current].end;
int cells = 0;
while(cells < max_cells) {
unicode_val_T data = utf_8_to_unicode(&text, end);
if (data == UCS_NO_CHAR) break;
cells += unicode_to_cell(data);
}
fs->state = (int)(text - fs->value);
}
#endif /* CONFIG_UTF_8 */
static int
#ifdef CONFIG_UTF_8
do_op_home(struct form_state *fs, struct line_info *line, int current, int utf8)
#else
do_op_home(struct form_state *fs, struct line_info *line, int current)
#endif /* CONFIG_UTF_8 */
{
if (current != -1) fs->state = line[current].start;
if (current == -1)
return 0;
#ifdef CONFIG_UTF_8
if (utf8)
fs->state = line[current - !!fs->state_cell].start;
else
#endif /* CONFIG_UTF_8 */
fs->state = line[current].start;
return 0;
}
#ifdef CONFIG_UTF_8
static int
do_op_up(struct form_state *fs, struct line_info *line, int current, int utf8)
{
int old_state;
if (current == -1) return 0;
if (!(current - !!fs->state_cell)) return 1;
if (!utf8) {
fs->state -= line[current].start - line[current-1].start;
int_upper_bound(&fs->state, line[current-1].end);
return 0;
}
old_state = fs->state;
if (fs->state_cell) {
int len = utf8_ptr2cells(fs->value + line[current - 1].start,
fs->value + fs->state_cell);
new_pos(fs, line, current - 2, len + line[current - 1].last_char_width);
} else {
int len = utf8_ptr2cells(fs->value + line[current].start,
fs->value + fs->state);
new_pos(fs, line, current - 1, len);
}
if (old_state != fs->state ) {
if (fs->state_cell && fs->state == line[current - 1].start) {
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state_cell = new_value - fs->value;
} else
fs->state_cell = 0;
}
return 0;
}
#else
static int
do_op_up(struct form_state *fs, struct line_info *line, int current)
{
@ -489,6 +835,49 @@ do_op_up(struct form_state *fs, struct line_info *line, int current)
int_upper_bound(&fs->state, line[current-1].end);
return 0;
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
static int
do_op_down(struct form_state *fs, struct line_info *line, int current, int utf8)
{
int old_state;
if (current == -1) return 0;
if (line[current + 1 - !!fs->state_cell].start == -1) return 1;
if (!utf8) {
fs->state += line[current+1].start - line[current].start;
int_upper_bound(&fs->state, line[current+1].end);
return 0;
}
old_state = fs->state;
if (fs->state_cell) {
int len = utf8_ptr2cells(fs->value + line[current - 1].start,
fs->value + fs->state_cell);
new_pos(fs, line, current, len + line[current - 1].last_char_width);
} else {
int len = utf8_ptr2cells(fs->value + line[current].start,
fs->value + fs->state);
new_pos(fs, line, current + 1, len);
}
if (old_state != fs->state ) {
if (fs->state_cell && fs->state == line[current+1].start) {
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state_cell = new_value - fs->value;
} else
fs->state_cell = 0;
}
return 0;
}
#else
static int
do_op_down(struct form_state *fs, struct line_info *line, int current)
@ -500,6 +889,39 @@ do_op_down(struct form_state *fs, struct line_info *line, int current)
int_upper_bound(&fs->state, line[current+1].end);
return 0;
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
static int
do_op_end(struct form_state *fs, struct line_info *line, int current, int utf8)
{
if (current == -1) {
fs->state = strlen(fs->value);
return 0;
}
if (!utf8) {
int wrap = line[current + 1].start == line[current].end;
/* Don't jump to next line when wrapping. */
fs->state = int_max(0, line[current].end - wrap);
return 0;
}
current -= !!fs->state_cell;
fs->state = line[current].end;
if (line[current].split_next) {
unsigned char *new_value;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
fs->state_cell = new_value - fs->value;
} else {
fs->state_cell = 0;
}
return 0;
}
#else
static int
do_op_end(struct form_state *fs, struct line_info *line, int current)
@ -515,9 +937,14 @@ do_op_end(struct form_state *fs, struct line_info *line, int current)
}
return 0;
}
#endif /* CONFIG_UTF_8 */
static int
#ifdef CONFIG_UTF_8
do_op_bob(struct form_state *fs, struct line_info *line, int current, int utf8)
#else
do_op_bob(struct form_state *fs, struct line_info *line, int current)
#endif /* CONFIG_UTF_8 */
{
if (current == -1) return 0;
@ -527,7 +954,11 @@ do_op_bob(struct form_state *fs, struct line_info *line, int current)
}
static int
#ifdef CONFIG_UTF_8
do_op_eob(struct form_state *fs, struct line_info *line, int current, int utf8)
#else
do_op_eob(struct form_state *fs, struct line_info *line, int current)
#endif /* CONFIG_UTF_8 */
{
if (current == -1) {
fs->state = strlen(fs->value);
@ -543,50 +974,102 @@ do_op_eob(struct form_state *fs, struct line_info *line, int current)
return 0;
}
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_home(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_home);
}
#else
enum frame_event_status
textarea_op_home(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_home);
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_up(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_up);
}
#else
enum frame_event_status
textarea_op_up(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_up);
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_down(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_down);
}
#else
enum frame_event_status
textarea_op_down(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_down);
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_end(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_end);
}
#else
enum frame_event_status
textarea_op_end(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_end);
}
#endif /* CONFIG_UTF_8 */
/* Set the form state so the cursor is on the first line of the buffer.
* Preserve the column if possible. */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_bob(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_bob);
}
#else
enum frame_event_status
textarea_op_bob(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_bob);
}
#endif /* CONFIG_UTF_8 */
/* Set the form state so the cursor is on the last line of the buffer. Preserve
* the column if possible. This is done by getting current and last line and
* then shifting the state by the delta of both lines start position bounding
* the whole thing to the end of the last line. */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_eob(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_eob);
}
#else
enum frame_event_status
textarea_op_eob(struct form_state *fs, struct form_control *fc)
{
return textarea_op(fs, fc, do_op_eob);
}
#endif /* CONFIG_UTF_8 */
enum frame_event_status
#ifdef CONFIG_UTF_8
textarea_op_enter(struct form_state *fs, struct form_control *fc, int utf8)
#else
textarea_op_enter(struct form_state *fs, struct form_control *fc)
#endif /* CONFIG_UTF_8 */
{
assert(fs && fs->value && fc);
if_assert_failed return FRAME_EVENT_OK;
@ -600,6 +1083,85 @@ textarea_op_enter(struct form_state *fs, struct form_control *fc)
return FRAME_EVENT_REFRESH;
}
#ifdef CONFIG_UTF_8
static int
do_op_left(struct form_state *fs, struct line_info *line, int current, int utf8)
{
int old_state;
int new_state;
unsigned char *new_value;
if (!utf8) {
fs->state = int_max(fs->state - 1, 0);
return 0;
}
if (fs->state_cell) {
fs->state = fs->state_cell;
fs->state_cell = 0;
return 0;
}
old_state = fs->state;
new_value = utf8_prevchar(fs->value + fs->state, 1, fs->value);
new_state = new_value - fs->value;
if (old_state != new_state) {
if (old_state == line[current].start && line[current].split_prev)
fs->state_cell = new_state;
else
fs->state = new_state;
}
return 0;
}
static int
do_op_right(struct form_state *fs, struct line_info *line, int current, int utf8)
{
unsigned char *text, *end;
int old_state;
if (!utf8) {
/* TODO: zle */
fs->state = int_min(fs->state + 1, strlen(fs->value));
return 0;
}
if (fs->state_cell) {
fs->state_cell = 0;
return 0;
}
text = fs->value + fs->state;
end = strchr(text, '\0');
old_state = fs->state;
utf_8_to_unicode(&text, end);
fs->state = text - fs->value;
if (old_state != fs->state && line[current].split_next) {
fs->state_cell = (fs->state == line[current].end) ? old_state:0;
} else if (!line[current].split_next) {
fs->state_cell = 0;
}
return 0;
}
#endif /* CONFIG_UTF_8 */
#ifdef CONFIG_UTF_8
enum frame_event_status
textarea_op_left(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_left);
}
enum frame_event_status
textarea_op_right(struct form_state *fs, struct form_control *fc, int utf8)
{
return textarea_op(fs, fc, utf8, do_op_right);
}
#endif /* CONFIG_UTF_8 */
void
set_textarea(struct document_view *doc_view, int direction)
@ -607,6 +1169,9 @@ set_textarea(struct document_view *doc_view, int direction)
struct form_control *fc;
struct form_state *fs;
struct link *link;
#ifdef CONFIG_UTF_8
int utf8 = doc_view->document->options.utf8;
#endif /* CONFIG_UTF_8 */
assert(doc_view && doc_view->vs && doc_view->document);
assert(direction == 1 || direction == -1);
@ -627,8 +1192,15 @@ set_textarea(struct document_view *doc_view, int direction)
/* Depending on which way we entered the textarea move cursor so that
* it is available at end or start. */
#ifdef CONFIG_UTF_8
if (direction == 1)
textarea_op_eob(fs, fc, utf8);
else
textarea_op_bob(fs, fc, utf8);
#else
if (direction == 1)
textarea_op_eob(fs, fc);
else
textarea_op_bob(fs, fc);
#endif /* CONFIG_UTF_8 */
}

View File

@ -13,7 +13,11 @@ struct link;
struct session;
struct terminal;
#ifdef CONFIG_UTF_8
int area_cursor(struct form_control *fc, struct form_state *fs, int utf8);
#else
int area_cursor(struct form_control *fc, struct form_state *fs);
#endif /* CONFIG_UTF_8 */
void draw_textarea(struct terminal *term, struct form_state *fs, struct document_view *doc_view, struct link *link);
unsigned char *encode_textarea(struct submitted_value *sv);
@ -21,6 +25,17 @@ extern int textarea_editor;
void textarea_edit(int, struct terminal *, struct form_state *, struct document_view *, struct link *);
void menu_textarea_edit(struct terminal *term, void *xxx, void *ses_);
#ifdef CONFIG_UTF_8
enum frame_event_status textarea_op_home(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_up(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_down(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_end(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_bob(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_eob(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_enter(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_left(struct form_state *fs, struct form_control *fc, int utf8);
enum frame_event_status textarea_op_right(struct form_state *fs, struct form_control *fc, int utf8);
#else
enum frame_event_status textarea_op_home(struct form_state *fs, struct form_control *fc);
enum frame_event_status textarea_op_up(struct form_state *fs, struct form_control *fc);
enum frame_event_status textarea_op_down(struct form_state *fs, struct form_control *fc);
@ -28,6 +43,7 @@ enum frame_event_status textarea_op_end(struct form_state *fs, struct form_contr
enum frame_event_status textarea_op_bob(struct form_state *fs, struct form_control *fc);
enum frame_event_status textarea_op_eob(struct form_state *fs, struct form_control *fc);
enum frame_event_status textarea_op_enter(struct form_state *fs, struct form_control *fc);
#endif /* CONFIG_UTF_8 */
void set_textarea(struct document_view *doc_view, int direction);