diff --git a/grid-utf8.c b/grid-utf8.c new file mode 100644 index 00000000..389c356e --- /dev/null +++ b/grid-utf8.c @@ -0,0 +1,96 @@ +/* $Id: grid-utf8.c,v 1.1 2009-11-19 22:23:27 tcunha Exp $ */ + +/* + * Copyright (c) 2009 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include + +#include "tmux.h" + +/* + * Grid UTF-8 utility functions. + */ + +/* Calculate UTF-8 grid cell size. Data is terminated by 0xff. */ +size_t +grid_utf8_size(const struct grid_utf8 *gu) +{ + size_t size; + + for (size = 0; size < sizeof gu->data; size++) { + if (gu->data[size] == 0xff) + break; + } + return (size); +} + +/* Copy UTF-8 out into a buffer. */ +size_t +grid_utf8_copy(const struct grid_utf8 *gu, char *buf, size_t len) +{ + size_t size; + + size = grid_utf8_size(gu); + if (size > len) + fatalx("UTF-8 copy overflow"); + memcpy(buf, gu->data, size); + return (size); +} + +/* Set UTF-8 grid data from input UTF-8. */ +void +grid_utf8_set(struct grid_utf8 *gu, const struct utf8_data *utf8data) +{ + if (utf8data->size == 0) + fatalx("UTF-8 data empty"); + if (utf8data->size > sizeof gu->data) + fatalx("UTF-8 data too long"); + memcpy(gu->data, utf8data->data, utf8data->size); + if (utf8data->size != sizeof gu->data) + gu->data[utf8data->size] = 0xff; + gu->width = utf8data->width; +} + +/* Append UTF-8 character onto the cell data (for combined characters). */ +int +grid_utf8_append(struct grid_utf8 *gu, const struct utf8_data *utf8data) +{ + size_t old_size; + + old_size = grid_utf8_size(gu); + if (old_size + utf8data->size > sizeof gu->data) + return (-1); + memcpy(gu->data + old_size, utf8data->data, utf8data->size); + if (old_size + utf8data->size != sizeof gu->data) + gu->data[old_size + utf8data->size] = 0xff; + return (0); +} + +/* Compare two UTF-8 cells. */ +int +grid_utf8_compare(const struct grid_utf8 *gu1, const struct grid_utf8 *gu2) +{ + size_t size; + + size = grid_utf8_size(gu1); + if (size != grid_utf8_size(gu2)) + return (0); + if (memcmp(gu1->data, gu2->data, size) != 0) + return (0); + return (1); +} diff --git a/grid.c b/grid.c index 3c092534..53b29e39 100644 --- a/grid.c +++ b/grid.c @@ -1,4 +1,4 @@ -/* $Id: grid.c,v 1.34 2009-10-15 01:55:12 tcunha Exp $ */ +/* $Id: grid.c,v 1.35 2009-11-19 22:23:27 tcunha Exp $ */ /* * Copyright (c) 2008 Nicholas Marriott @@ -502,8 +502,8 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) const struct grid_cell *gc; const struct grid_utf8 *gu; char *buf; - size_t len, off; - u_int xx, i; + size_t len, off, size; + u_int xx; GRID_DEBUG(gd, "px=%u, py=%u, nx=%u", px, py, nx); @@ -517,17 +517,15 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx) continue; if (gc->flags & GRID_FLAG_UTF8) { - while (len < off + UTF8_SIZE + 1) { + gu = grid_peek_utf8(gd, xx, py); + + size = grid_utf8_size(gu); + while (len < off + size + 1) { buf = xrealloc(buf, 2, len); len *= 2; } - gu = grid_peek_utf8(gd, xx, py); - for (i = 0; i < UTF8_SIZE; i++) { - if (gu->data[i] == 0xff) - break; - buf[off++] = gu->data[i]; - } + off += grid_utf8_copy(gu, buf + off, len - off); } else { while (len < off + 2) { buf = xrealloc(buf, 2, len); diff --git a/screen-write.c b/screen-write.c index 88215b51..6843a053 100644 --- a/screen-write.c +++ b/screen-write.c @@ -1,4 +1,4 @@ -/* $Id: screen-write.c,v 1.85 2009-11-18 01:25:35 tcunha Exp $ */ +/* $Id: screen-write.c,v 1.86 2009-11-19 22:23:27 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -354,7 +354,7 @@ screen_write_copy(struct screen_write_ctx *ctx, const struct grid_cell *gc; const struct grid_utf8 *gu; struct utf8_data utf8data; - u_int xx, yy, cx, cy, ax, bx, i; + u_int xx, yy, cx, cy, ax, bx; cx = s->cx; cy = s->cy; @@ -381,18 +381,15 @@ screen_write_copy(struct screen_write_ctx *ctx, gc = &grid_default_cell; else gc = &gl->celldata[xx]; - if (gc->flags & GRID_FLAG_UTF8) { - gu = &gl->utf8data[xx]; - memcpy(utf8data.data, - gu->data, sizeof utf8data.data); - utf8data.width = gu->width; - utf8data.size = 0; - for (i = 0; i < UTF8_SIZE; i++) { - if (gu->data[i] == 0xff) - break; - utf8data.size++; - } + if (!(gc->flags & GRID_FLAG_UTF8)) { + screen_write_cell(ctx, gc, NULL); + continue; } + /* Reinject the UTF-8 sequence. */ + gu = &gl->utf8data[xx]; + utf8data.size = grid_utf8_copy( + gu, utf8data.data, sizeof utf8data.data); + utf8data.width = gu->width; screen_write_cell(ctx, gc, &utf8data); } if (px + nx == gd->sx && px + nx > gl->cellsize) @@ -1037,13 +1034,7 @@ screen_write_cell(struct screen_write_ctx *ctx, grid_view_set_cell(gd, s->cx, s->cy, gc); if (gc->flags & GRID_FLAG_UTF8) { /* Construct UTF-8 and write it. */ - gu.width = utf8data->width; - memset(gu.data, 0xff, sizeof gu.data); - if (utf8data->size == 0) - fatalx("UTF-8 data empty"); - if (utf8data->size > sizeof gu.data) - fatalx("UTF-8 data overflow"); - memcpy(gu.data, utf8data->data, utf8data->size); + grid_utf8_set(&gu, utf8data); grid_view_set_utf8(gd, s->cx, s->cy, &gu); } @@ -1080,7 +1071,7 @@ screen_write_combine( struct grid *gd = s->grid; struct grid_cell *gc; struct grid_utf8 *gu, tmp_gu; - u_int i, old_size; + u_int i; /* Can't combine if at 0. */ if (s->cx == 0) @@ -1093,35 +1084,30 @@ screen_write_combine( /* Retrieve the previous cell and convert to UTF-8 if not already. */ gc = grid_view_get_cell(gd, s->cx - 1, s->cy); if (!(gc->flags & GRID_FLAG_UTF8)) { - memset(&tmp_gu.data, 0xff, sizeof tmp_gu.data); - *tmp_gu.data = gc->data; + tmp_gu.data[0] = gc->data; + tmp_gu.data[1] = 0xff; tmp_gu.width = 1; grid_view_set_utf8(gd, s->cx - 1, s->cy, &tmp_gu); gc->flags |= GRID_FLAG_UTF8; } - /* Get the previous cell's UTF-8 data and its size. */ + /* Append the current cell. */ gu = grid_view_get_utf8(gd, s->cx - 1, s->cy); - for (old_size = 0; old_size < UTF8_SIZE; old_size++) { - if (gu->data[old_size] == 0xff) - break; + if (grid_utf8_append(gu, utf8data) != 0) { + /* Failed: scrap this character and replace with underscores. */ + if (gu->width == 1) { + gc->data = '_'; + gc->flags &= ~GRID_FLAG_UTF8; + } else { + for (i = 0; i < gu->width && i != sizeof gu->data; i++) + gu->data[i] = '_'; + if (i != sizeof gu->data) + gu->data[i] = 0xff; + gu->width = i; + } } - /* If there isn't space, scrap this character. */ - if (old_size + utf8data->size > UTF8_SIZE) { - for (i = 0; i < gu->width && i != UTF8_SIZE; i++) - gu->data[i] = '_'; - if (i != UTF8_SIZE) - gu->data[i] = 0xff; - gu->width = i; - return (0); - } - - /* Otherwise save the character. */ - memcpy(gu->data + old_size, utf8data->data, utf8data->size); - if (old_size + utf8data->size != UTF8_SIZE) - gu->data[old_size + utf8data->size] = 0xff; return (0); } diff --git a/tmux.1 b/tmux.1 index beb13f00..0713bdbb 100644 --- a/tmux.1 +++ b/tmux.1 @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.202 2009-11-19 22:20:04 tcunha Exp $ +.\" $Id: tmux.1,v 1.203 2009-11-19 22:23:27 tcunha Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott .\" @@ -454,7 +454,7 @@ with .D1 (alias: Ic rename ) Rename the session to .Ar new-name . -.It Xo Ic show-messages +.It Xo Ic show-messages .Op Fl t Ar target-client .Xc .D1 (alias: Ic showmsgs ) diff --git a/tmux.h b/tmux.h index 35e38066..a555d604 100644 --- a/tmux.h +++ b/tmux.h @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.518 2009-11-19 22:20:04 tcunha Exp $ */ +/* $Id: tmux.h,v 1.519 2009-11-19 22:23:27 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -73,6 +73,12 @@ extern char **environ; #define PRINT_LENGTH 512 /* printed error/message size */ #define ENVIRON_LENGTH 1024 /* environment variable length */ +/* + * UTF-8 data size. This must be big enough to hold combined characters as well + * as single. + */ +#define UTF8_SIZE 9 + /* Fatal errors. */ #define fatal(msg) log_fatal("%s: %s", __func__, msg); #define fatalx(msg) log_fatalx("%s: %s", __func__, msg); @@ -524,13 +530,12 @@ struct mode_key_table { #define MODE_MOUSE 0x10 /* - * A single UTF-8 character. + * A single UTF-8 character. * * The data member in this must be UTF8_SIZE to allow screen_write_copy to * reinject stored UTF-8 data back into screen_write_cell after combining (ugh * XXX XXX). */ -#define UTF8_SIZE 9 struct utf8_data { u_char data[UTF8_SIZE]; @@ -1674,6 +1679,13 @@ char *grid_string_cells(struct grid *, u_int, u_int, u_int); void grid_duplicate_lines( struct grid *, u_int, struct grid *, u_int, u_int); +/* grid-utf8.c */ +size_t grid_utf8_size(const struct grid_utf8 *); +size_t grid_utf8_copy(const struct grid_utf8 *, char *, size_t); +void grid_utf8_set(struct grid_utf8 *, const struct utf8_data *); +int grid_utf8_append(struct grid_utf8 *, const struct utf8_data *); +int grid_utf8_compare(const struct grid_utf8 *, const struct grid_utf8 *); + /* grid-view.c */ const struct grid_cell *grid_view_peek_cell(struct grid *, u_int, u_int); struct grid_cell *grid_view_get_cell(struct grid *, u_int, u_int); diff --git a/tty.c b/tty.c index a5e1770b..b163552e 100644 --- a/tty.c +++ b/tty.c @@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.174 2009-11-13 16:57:21 tcunha Exp $ */ +/* $Id: tty.c,v 1.175 2009-11-19 22:23:27 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -370,16 +370,12 @@ tty_putc(struct tty *tty, u_char ch) void tty_pututf8(struct tty *tty, const struct grid_utf8 *gu) { - u_int i; - - for (i = 0; i < UTF8_SIZE; i++) { - if (gu->data[i] == 0xff) - break; - bufferevent_write(tty->event, &gu->data[i], 1); - if (tty->log_fd != -1) - write(tty->log_fd, &gu->data[i], 1); - } + size_t size; + size = grid_utf8_size(gu); + bufferevent_write(tty->event, gu->data, size); + if (tty->log_fd != -1) + write(tty->log_fd, gu->data, size); tty->cx += gu->width; } diff --git a/window-copy.c b/window-copy.c index c2a796e0..54d53432 100644 --- a/window-copy.c +++ b/window-copy.c @@ -1,4 +1,4 @@ -/* $Id: window-copy.c,v 1.90 2009-10-23 17:17:20 tcunha Exp $ */ +/* $Id: window-copy.c,v 1.91 2009-11-19 22:23:27 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -486,6 +486,7 @@ window_copy_search_compare( { const struct grid_cell *gc, *sgc; const struct grid_utf8 *gu, *sgu; + size_t size; gc = grid_peek_cell(gd, px, py); sgc = grid_peek_cell(sgd, spx, 0); @@ -496,7 +497,7 @@ window_copy_search_compare( if (gc->flags & GRID_FLAG_UTF8) { gu = grid_peek_utf8(gd, px, py); sgu = grid_peek_utf8(sgd, spx, 0); - if (memcmp(gu->data, sgu->data, UTF8_SIZE) == 0) + if (grid_utf8_compare(gu, sgu)) return (1); } else { if (gc->data == sgc->data) @@ -895,7 +896,8 @@ window_copy_copy_line(struct window_pane *wp, const struct grid_cell *gc; const struct grid_utf8 *gu; struct grid_line *gl; - u_int i, j, xx, wrapped = 0; + u_int i, xx, wrapped = 0; + size_t size; if (sx > ex) return; @@ -928,12 +930,9 @@ window_copy_copy_line(struct window_pane *wp, (*buf)[(*off)++] = gc->data; } else { gu = grid_peek_utf8(gd, i, sy); - *buf = xrealloc(*buf, 1, (*off) + UTF8_SIZE); - for (j = 0; j < UTF8_SIZE; j++) { - if (gu->data[j] == 0xff) - break; - (*buf)[(*off)++] = gu->data[j]; - } + size = grid_utf8_size(gu); + *buf = xrealloc(*buf, 1, (*off) + size); + *off += grid_utf8_copy(gu, *buf + *off, size); } } }