mirror of
https://github.com/irssi/irssi.git
synced 2026-08-23 10:32:31 +02:00
Merge f5033031b1 into 1cfec5f63d
This commit is contained in:
commit
66ea96978f
11 changed files with 249 additions and 96 deletions
|
|
@ -44,6 +44,8 @@ libcore_a_SOURCES = \
|
|||
settings.c \
|
||||
signals.c \
|
||||
special-vars.c \
|
||||
utf8.c \
|
||||
wcwidth.c \
|
||||
write-buffer.c
|
||||
|
||||
structure_headers = \
|
||||
|
|
|
|||
|
|
@ -25,10 +25,7 @@
|
|||
#include "settings.h"
|
||||
#include "servers.h"
|
||||
#include "misc.h"
|
||||
|
||||
#define ALIGN_RIGHT 0x01
|
||||
#define ALIGN_CUT 0x02
|
||||
#define ALIGN_PAD 0x04
|
||||
#include "utf8.h"
|
||||
|
||||
#define isvarchar(c) \
|
||||
(i_isalnum(c) || (c) == '_')
|
||||
|
|
@ -316,31 +313,79 @@ static int get_alignment_args(char **data, int *align, int *flags, char *pad)
|
|||
}
|
||||
|
||||
/* return the aligned text */
|
||||
static char *get_alignment(const char *text, int align, int flags, char pad)
|
||||
char *get_alignment(const char *text, int align, int flags, char pad)
|
||||
{
|
||||
GString *str;
|
||||
char *ret;
|
||||
gchar *ret;
|
||||
gchar *ret_p;
|
||||
uint i;
|
||||
/* Terminology: width is an amount of columns, length is an amount of
|
||||
* characters.
|
||||
*/
|
||||
uint start_width, start_length;
|
||||
uint cut_width, cut_length;
|
||||
uint final_width, final_length;
|
||||
uint pad_count;
|
||||
uint delta;
|
||||
|
||||
g_return_val_if_fail(text != NULL, NULL);
|
||||
|
||||
str = g_string_new(text);
|
||||
/* abort if non-valid UTF-8 */
|
||||
if (!g_utf8_validate(text, -1, NULL))
|
||||
return NULL;
|
||||
|
||||
/* cut */
|
||||
if ((flags & ALIGN_CUT) && align > 0 && str->len > align)
|
||||
g_string_truncate(str, align);
|
||||
/* how many columns and chars do we have in the first place? */
|
||||
start_width = get_utf8_string_width(text, 1 /* skip UTF-8 validation */);
|
||||
start_length = g_utf8_strlen(text, 1024);
|
||||
/* how many columns and chars will we have after the cut? */
|
||||
cut_width = start_width;
|
||||
cut_length = start_length;
|
||||
delta = 0;
|
||||
if ((flags & ALIGN_CUT) && align > 0 && start_width > align) {
|
||||
cut_width = align;
|
||||
cut_length = get_utf8_chars_for_width(text,
|
||||
align,
|
||||
1 /* skip UTF-8 validation */,
|
||||
&delta);
|
||||
/* At this point, we know that we have to take "cut_length" chars from
|
||||
* "text" and append "delta" padding chars to reach "align" columns.
|
||||
*/
|
||||
}
|
||||
/* how many columns will we have after the pad? */
|
||||
final_width = cut_width;
|
||||
final_length = cut_length;
|
||||
pad_count = delta;
|
||||
if ((flags & ALIGN_PAD) && align > cut_width) {
|
||||
final_width = align;
|
||||
pad_count += (final_width - cut_width);
|
||||
final_length += pad_count;
|
||||
}
|
||||
|
||||
/* add pad characters */
|
||||
if (flags & ALIGN_PAD) {
|
||||
while (str->len < align) {
|
||||
if (flags & ALIGN_RIGHT)
|
||||
g_string_prepend_c(str, pad);
|
||||
else
|
||||
g_string_append_c(str, pad);
|
||||
/* allocate 4 bytes for each character we will have in the end */
|
||||
ret = g_malloc((4 * final_length) + 1);
|
||||
ret_p = ret;
|
||||
|
||||
/* left pad to align right, if necessary */
|
||||
if (pad_count && (flags & ALIGN_RIGHT)) {
|
||||
for (i = 0; i < pad_count; i++) {
|
||||
*ret_p = pad;
|
||||
ret_p ++;
|
||||
}
|
||||
}
|
||||
|
||||
ret = str->str;
|
||||
g_string_free(str, FALSE);
|
||||
/* copy the original string (either n characters or the whole of it) */
|
||||
g_utf8_strncpy(ret_p, text, cut_length);
|
||||
/* sadly, at this point, we have no idea where g_utf8_strncpy put the trailing \0... */
|
||||
ret_p += strlen(ret_p);
|
||||
|
||||
/* right pad to align left, if necessary */
|
||||
if (pad_count && !(flags & ALIGN_RIGHT)) {
|
||||
for (i = 0; i < pad_count; i++) {
|
||||
*ret_p = pad;
|
||||
ret_p ++;
|
||||
}
|
||||
*ret_p = '\0';
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,17 @@
|
|||
#define PARSE_FLAG_ESCAPE_THEME 0x08 /* if any arguments/variables contain { or } chars, escape them with % */
|
||||
#define PARSE_FLAG_ONLY_ARGS 0x10 /* expand only arguments ($0 $1 etc.) but no other $variables */
|
||||
|
||||
#define ALIGN_RIGHT 0x01
|
||||
#define ALIGN_CUT 0x02
|
||||
#define ALIGN_PAD 0x04
|
||||
|
||||
typedef char* (*SPECIAL_HISTORY_FUNC)
|
||||
(const char *text, void *item, int *free_ret);
|
||||
|
||||
|
||||
/* Cut and/or pad text so it takes exactly "align" characters on the screen */
|
||||
char *get_alignment(const char *text, int align, int flags, char pad);
|
||||
|
||||
/* Parse and expand text after '$' character. return value has to be
|
||||
g_free()'d if `free_ret' is TRUE. */
|
||||
char *parse_special(char **cmd, SERVER_REC *server, void *item,
|
||||
|
|
|
|||
124
src/core/utf8.c
Normal file
124
src/core/utf8.c
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/* utf8.c - Operations on UTF-8 strings.
|
||||
*
|
||||
* Copyright (C) 2002 Timo Sirainen
|
||||
*
|
||||
* Based on GLib code by
|
||||
*
|
||||
* Copyright (C) 1999 Tom Tromey
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include "module.h"
|
||||
|
||||
/*
|
||||
* Return the width (number of columns when displayed) of the character pointed
|
||||
* by c.
|
||||
*/
|
||||
int get_utf8_char_width(const gchar *c) {
|
||||
gunichar uc;
|
||||
int char_width;
|
||||
uc = g_utf8_get_char(c);
|
||||
char_width = g_unichar_isprint(uc) ? (1 + g_unichar_iswide(uc)) : 0;
|
||||
return char_width;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of columns taken by the s string, assuming its end is
|
||||
* marked with a '\0' character and assuming it is a UTF-8 (multibyte) string.
|
||||
* If s is NULL, this function returns -1.
|
||||
* By default, this function takes care to validate s by calling
|
||||
* g_utf8_validate(s, -1, NULL). If this check is deemed unnecessary, passing a
|
||||
* non-zero value as skip_validation will skip that step. If the validation
|
||||
* fails, this function returns -1. Otherwise, it will strive to provide a
|
||||
* value as close as possible to what is expected.
|
||||
*/
|
||||
int get_utf8_string_width(const gchar *s, int skip_validation) {
|
||||
const gchar *c;
|
||||
int str_width;
|
||||
|
||||
/* Ensure s is non-NULL: */
|
||||
if (!s) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Validate the string, unless required otherwise: */
|
||||
if (!skip_validation) {
|
||||
if (!g_utf8_validate(s, -1, NULL)) {
|
||||
/* Another possibility here would be to return strlen(s). */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate over characters to determine the width: */
|
||||
str_width = 0;
|
||||
for (c = s; *c; c = g_utf8_next_char(c)) {
|
||||
str_width += get_utf8_char_width(c);
|
||||
}
|
||||
/* Note: there probably are some Unicode subtleties (Fitzpatrick
|
||||
* modifiers?) that make the above implementation somewhat naive, but we
|
||||
* have to start somewhere.
|
||||
*/
|
||||
return str_width;
|
||||
}
|
||||
|
||||
/* Return the amount of characters from s it takes to reach n columns, or -1 if
|
||||
* s is NULL.
|
||||
*/
|
||||
int get_utf8_chars_for_width(const gchar *s, unsigned int n, int skip_validation, unsigned int *delta) {
|
||||
const gchar *c;
|
||||
int str_width, char_width, char_count;
|
||||
|
||||
/* Ensure s is non-NULL: */
|
||||
if (!s) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Handle the dummy case where n is 0: */
|
||||
if (!n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Validate the string, unless required otherwise: */
|
||||
if (!skip_validation) {
|
||||
if (!g_utf8_validate(s, -1, NULL)) {
|
||||
/* Another possibility here would be to return strlen(s). */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate over characters until we reach n: */
|
||||
char_count = 0;
|
||||
str_width = 0;
|
||||
for (c = s; *c; c = g_utf8_next_char(c)) {
|
||||
char_width = get_utf8_char_width(c);
|
||||
if (str_width + char_width > n) {
|
||||
/* We are about to exceed n, stop here. */
|
||||
break;
|
||||
}
|
||||
++ char_count;
|
||||
str_width += char_width;
|
||||
}
|
||||
/* At this point, we know that char_count characters reach str_width
|
||||
* columns, which is less than or equal to n. */
|
||||
|
||||
/* Optionally provide the delta between str_width and n */
|
||||
if (delta) {
|
||||
*delta = n - str_width;
|
||||
}
|
||||
return char_count;
|
||||
}
|
||||
|
|
@ -8,9 +8,16 @@
|
|||
#define is_big5_hi(hi) (0x81 <= (hi) && (hi) <= 0xFE)
|
||||
#define is_big5(hi,lo) (is_big5_hi(hi) && is_big5_lo(lo))
|
||||
|
||||
typedef guint32 unichar;
|
||||
|
||||
/* Returns width for character (0-2). */
|
||||
int mk_wcwidth(unichar c);
|
||||
|
||||
/* Return the number of columns occupied by a given string. */
|
||||
int get_utf8_char_width(const gchar *);
|
||||
int get_utf8_string_width(const gchar *, int);
|
||||
int get_utf8_chars_for_width(const gchar *, unsigned int, int, unsigned int *);
|
||||
|
||||
#define unichar_isprint(c) (((c) & ~0x80) >= 32)
|
||||
#define is_utf8_leading(c) (((c) & 0xc0) != 0x80)
|
||||
|
||||
|
|
@ -60,6 +60,7 @@
|
|||
*/
|
||||
|
||||
#include "module.h"
|
||||
#include "utf8.h"
|
||||
|
||||
struct interval {
|
||||
int first;
|
||||
|
|
@ -24,8 +24,6 @@ libfe_common_core_a_SOURCES = \
|
|||
fe-queries.c \
|
||||
fe-server.c \
|
||||
fe-settings.c \
|
||||
utf8.c \
|
||||
wcwidth.c \
|
||||
formats.c \
|
||||
hilight-text.c \
|
||||
keyboard.c \
|
||||
|
|
@ -62,6 +60,3 @@ pkginc_fe_common_core_HEADERS = \
|
|||
window-items.h \
|
||||
windows-layout.h \
|
||||
fe-windows.h
|
||||
|
||||
noinst_HEADERS = \
|
||||
utf8.h
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#include "levels.h"
|
||||
#include "misc.h"
|
||||
#include "settings.h"
|
||||
#include "special-vars.h"
|
||||
#include "utf8.h"
|
||||
|
||||
#include "chat-protocols.h"
|
||||
#include "chatnets.h"
|
||||
|
|
@ -323,7 +325,7 @@ static void cmd_channel_remove(const char *data)
|
|||
|
||||
static int get_nick_length(void *data)
|
||||
{
|
||||
return strlen(((NICK_REC *) data)->nick);
|
||||
return get_utf8_string_width(((NICK_REC *) data)->nick, 1024);
|
||||
}
|
||||
|
||||
static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
||||
|
|
@ -333,9 +335,9 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
|||
GString *str;
|
||||
GSList *tmp;
|
||||
char *format, *stripped, *prefix_format;
|
||||
char *linebuf, nickmode[2] = { 0, 0 };
|
||||
char *aligned_nick, nickmode[2] = { 0, 0 };
|
||||
int *columns, cols, rows, last_col_rows, col, row, max_width;
|
||||
int item_extra, linebuf_size, formatnum;
|
||||
int item_extra, formatnum;
|
||||
|
||||
window = window_find_closest(channel->server, channel->visible_name,
|
||||
MSGLEVEL_CLIENTCRAP);
|
||||
|
|
@ -394,7 +396,6 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
|||
last_col_rows = rows;
|
||||
|
||||
str = g_string_new(prefix_format);
|
||||
linebuf_size = max_width+1; linebuf = g_malloc(linebuf_size);
|
||||
|
||||
col = 0; row = 0;
|
||||
for (tmp = nicklist; tmp != NULL; tmp = tmp->next) {
|
||||
|
|
@ -405,13 +406,9 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
|||
else
|
||||
nickmode[0] = ' ';
|
||||
|
||||
if (linebuf_size < columns[col]-item_extra+1) {
|
||||
linebuf_size = (columns[col]-item_extra+1)*2;
|
||||
linebuf = g_realloc(linebuf, linebuf_size);
|
||||
}
|
||||
memset(linebuf, ' ', columns[col]-item_extra);
|
||||
linebuf[columns[col]-item_extra] = '\0';
|
||||
memcpy(linebuf, rec->nick, strlen(rec->nick));
|
||||
aligned_nick = get_alignment(rec->nick,
|
||||
columns[col]-item_extra,
|
||||
ALIGN_PAD, ' ');
|
||||
|
||||
formatnum = rec->op ? TXT_NAMES_NICK_OP :
|
||||
rec->halfop ? TXT_NAMES_NICK_HALFOP :
|
||||
|
|
@ -420,8 +417,9 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
|||
format = format_get_text(MODULE_NAME, NULL,
|
||||
channel->server,
|
||||
channel->visible_name,
|
||||
formatnum, nickmode, linebuf);
|
||||
formatnum, nickmode, aligned_nick);
|
||||
g_string_append(str, format);
|
||||
g_free(aligned_nick);
|
||||
g_free(format);
|
||||
|
||||
if (++col == cols) {
|
||||
|
|
@ -446,7 +444,6 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist)
|
|||
g_string_free(str, TRUE);
|
||||
g_free_not_null(columns);
|
||||
g_free_not_null(prefix_format);
|
||||
g_free(linebuf);
|
||||
}
|
||||
|
||||
void fe_channels_nicklist(CHANNEL_REC *channel, int flags)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#define MODULE_NAME "fe-common/core"
|
||||
|
||||
typedef guint32 unichar;
|
||||
#include "utf8.h"
|
||||
typedef struct {
|
||||
time_t time;
|
||||
char *nick;
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
/* utf8.c - Operations on UTF-8 strings.
|
||||
*
|
||||
* Copyright (C) 2002 Timo Sirainen
|
||||
*
|
||||
* Based on GLib code by
|
||||
*
|
||||
* Copyright (C) 1999 Tom Tromey
|
||||
* Copyright (C) 2000 Red Hat, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "module.h"
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ typedef struct _TERM_WINDOW TERM_WINDOW;
|
|||
#define TERM_TYPE_UTF8 1
|
||||
#define TERM_TYPE_BIG5 2
|
||||
|
||||
typedef guint32 unichar;
|
||||
#include "utf8.h"
|
||||
|
||||
extern TERM_WINDOW *root_window;
|
||||
extern int term_width, term_height;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue