mirror of
https://github.com/weechat/weechat.git
synced 2026-06-12 14:14:48 +02:00
c28696e602
Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
365 lines
9.9 KiB
C
365 lines
9.9 KiB
C
/*
|
|
* gui-nick.c - nick functions (used by all GUI)
|
|
*
|
|
* Copyright (C) 2003-2024 Sébastien Helleu <flashcode@flashtux.org>
|
|
*
|
|
* This file is part of WeeChat, the extensible chat client.
|
|
*
|
|
* WeeChat is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* WeeChat is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "../core/weechat.h"
|
|
#include "../core/core-config.h"
|
|
#include "../core/core-hashtable.h"
|
|
#include "../core/core-string.h"
|
|
#include "../core/core-utf8.h"
|
|
#include "gui-nick.h"
|
|
#include "gui-color.h"
|
|
|
|
|
|
/*
|
|
* Hashes a string with a variant of djb2 hash, using 64-bit integer.
|
|
*
|
|
* Number pointed by *color_64 is updated by the function.
|
|
*/
|
|
|
|
void
|
|
gui_nick_hash_djb2_64 (const char *nickname, uint64_t *color_64)
|
|
{
|
|
while (nickname && nickname[0])
|
|
{
|
|
*color_64 ^= (*color_64 << 5) + (*color_64 >> 2) +
|
|
utf8_char_int (nickname);
|
|
nickname = utf8_next_char (nickname);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Hashes a string with a variant of djb2 hash, using 32-bit integer.
|
|
*
|
|
* Number pointed by *color_32 is updated by the function.
|
|
*/
|
|
|
|
void
|
|
gui_nick_hash_djb2_32 (const char *nickname, uint32_t *color_32)
|
|
{
|
|
while (nickname && nickname[0])
|
|
{
|
|
*color_32 ^= (*color_32 << 5) + (*color_32 >> 2) +
|
|
utf8_char_int (nickname);
|
|
nickname = utf8_next_char (nickname);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Hashes a string with sum of letters, using 64-bit integer.
|
|
*
|
|
* Number pointed by *color_64 is updated by the function.
|
|
*/
|
|
|
|
void
|
|
gui_nick_hash_sum_64 (const char *nickname, uint64_t *color_64)
|
|
{
|
|
while (nickname && nickname[0])
|
|
{
|
|
*color_64 += utf8_char_int (nickname);
|
|
nickname = utf8_next_char (nickname);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Hashes a string with sum of letters, using 32-bit integer.
|
|
*
|
|
* Number pointed by *color_32 is updated by the function.
|
|
*/
|
|
|
|
void
|
|
gui_nick_hash_sum_32 (const char *nickname, uint32_t *color_32)
|
|
{
|
|
while (nickname && nickname[0])
|
|
{
|
|
*color_32 += utf8_char_int (nickname);
|
|
nickname = utf8_next_char (nickname);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Hashes a nickname to find color.
|
|
*
|
|
* Returns a number which is between 0 and num_colors - 1 (inclusive).
|
|
*
|
|
* num_colors is commonly the number of colors in the option
|
|
* "weechat.color.chat_nick_colors".
|
|
* If num_colors is < 0, the hash itself is returned (64-bit unsigned number).
|
|
*/
|
|
|
|
uint64_t
|
|
gui_nick_hash_color (const char *nickname, int num_colors)
|
|
{
|
|
const char *ptr_salt;
|
|
uint64_t color_64;
|
|
uint32_t color_32;
|
|
|
|
if (!nickname || !nickname[0])
|
|
return 0;
|
|
|
|
if (num_colors == 0)
|
|
return 0;
|
|
|
|
ptr_salt = CONFIG_STRING(config_look_nick_color_hash_salt);
|
|
|
|
color_64 = 0;
|
|
|
|
switch (CONFIG_ENUM(config_look_nick_color_hash))
|
|
{
|
|
case CONFIG_LOOK_NICK_COLOR_HASH_DJB2:
|
|
/* variant of djb2 hash, using 64-bit integer */
|
|
color_64 = 5381;
|
|
gui_nick_hash_djb2_64 (ptr_salt, &color_64);
|
|
gui_nick_hash_djb2_64 (nickname, &color_64);
|
|
break;
|
|
case CONFIG_LOOK_NICK_COLOR_HASH_SUM:
|
|
/* sum of letters, using 64-bit integer */
|
|
color_64 = 0;
|
|
gui_nick_hash_sum_64 (ptr_salt, &color_64);
|
|
gui_nick_hash_sum_64 (nickname, &color_64);
|
|
break;
|
|
case CONFIG_LOOK_NICK_COLOR_HASH_DJB2_32:
|
|
/* variant of djb2 hash, using 32-bit integer */
|
|
color_32 = 5381;
|
|
gui_nick_hash_djb2_32 (ptr_salt, &color_32);
|
|
gui_nick_hash_djb2_32 (nickname, &color_32);
|
|
color_64 = color_32;
|
|
break;
|
|
case CONFIG_LOOK_NICK_COLOR_HASH_SUM_32:
|
|
/* sum of letters, using 32-bit integer */
|
|
color_32 = 0;
|
|
gui_nick_hash_sum_32 (ptr_salt, &color_32);
|
|
gui_nick_hash_sum_32 (nickname, &color_32);
|
|
color_64 = color_32;
|
|
break;
|
|
}
|
|
|
|
return (num_colors > 0) ? color_64 % num_colors : color_64;
|
|
}
|
|
|
|
/*
|
|
* Gets forced color for a nick.
|
|
*
|
|
* Returns the name of color (for example: "green"), NULL if no color is forced
|
|
* for nick.
|
|
*/
|
|
|
|
const char *
|
|
gui_nick_get_forced_color (const char *nickname)
|
|
{
|
|
const char *forced_color;
|
|
char *nick_lower;
|
|
|
|
if (!nickname || !nickname[0])
|
|
return NULL;
|
|
|
|
forced_color = hashtable_get (config_hashtable_nick_color_force, nickname);
|
|
if (forced_color)
|
|
return forced_color;
|
|
|
|
nick_lower = string_tolower (nickname);
|
|
if (nick_lower)
|
|
{
|
|
forced_color = hashtable_get (config_hashtable_nick_color_force,
|
|
nick_lower);
|
|
free (nick_lower);
|
|
}
|
|
|
|
return forced_color;
|
|
}
|
|
|
|
/*
|
|
* Duplicates a nick and stops at first char in list (using option
|
|
* weechat.look.nick_color_stop_chars).
|
|
*
|
|
* Note: result must be freed after use.
|
|
*/
|
|
|
|
char *
|
|
gui_nick_strdup_for_color (const char *nickname)
|
|
{
|
|
int char_size, other_char_seen;
|
|
char *result, *pos, utf_char[16];
|
|
|
|
if (!nickname)
|
|
return NULL;
|
|
|
|
result = malloc (strlen (nickname) + 1);
|
|
pos = result;
|
|
other_char_seen = 0;
|
|
while (nickname[0])
|
|
{
|
|
char_size = utf8_char_size (nickname);
|
|
memcpy (utf_char, nickname, char_size);
|
|
utf_char[char_size] = '\0';
|
|
|
|
if (strstr (CONFIG_STRING(config_look_nick_color_stop_chars),
|
|
utf_char))
|
|
{
|
|
if (other_char_seen)
|
|
{
|
|
pos[0] = '\0';
|
|
return result;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
other_char_seen = 1;
|
|
}
|
|
memcpy (pos, utf_char, char_size);
|
|
pos += char_size;
|
|
|
|
nickname += char_size;
|
|
}
|
|
pos[0] = '\0';
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Finds a color name for a nick (according to nick letters).
|
|
*
|
|
* If case_range < 0, nick is case-sensitive.
|
|
* If case_range == 0, nick is converted to lower case (with string_tolower).
|
|
* If case_range > 0, nick is converted to lower case (with string_tolower_range).
|
|
*
|
|
* If colors is NULL (most common case), the color returned is either a forced
|
|
* color (from option "weechat.look.nick_color_force") or a color from option
|
|
* "weechat.color.chat_nick_colors".
|
|
*
|
|
* If colors is set and not empty, a color from this list is returned
|
|
* (format of argument: comma-separated list of colors, a background is
|
|
* allowed with format "fg:bg", for example: "blue,yellow:red" for blue and
|
|
* yellow on red).
|
|
*
|
|
* Returns the name of a color (for example: "green").
|
|
*
|
|
* Note: result must be freed after use.
|
|
*/
|
|
|
|
char *
|
|
gui_nick_find_color_name (const char *nickname, int case_range,
|
|
const char *colors)
|
|
{
|
|
int color, num_colors;
|
|
char *nickname2, *nickname3, **list_colors, *result;
|
|
const char *forced_color, *ptr_result;
|
|
static char *default_color = "default";
|
|
|
|
list_colors = NULL;
|
|
num_colors = 0;
|
|
nickname2 = NULL;
|
|
nickname3 = NULL;
|
|
ptr_result = NULL;
|
|
|
|
if (!nickname || !nickname[0])
|
|
goto end;
|
|
|
|
if (colors && colors[0])
|
|
{
|
|
list_colors = string_split (colors, ",", NULL, 0, 0, &num_colors);
|
|
if (!list_colors || (num_colors == 0))
|
|
goto end;
|
|
}
|
|
|
|
nickname2 = gui_nick_strdup_for_color (nickname);
|
|
if (!nickname2)
|
|
goto end;
|
|
|
|
if (!list_colors)
|
|
{
|
|
/* look if color is forced for the nick */
|
|
forced_color = gui_nick_get_forced_color (nickname2);
|
|
if (forced_color)
|
|
{
|
|
ptr_result = forced_color;
|
|
goto end;
|
|
}
|
|
/* ensure nick colors are properly set */
|
|
if (!config_nick_colors)
|
|
config_set_nick_colors ();
|
|
if (config_num_nick_colors == 0)
|
|
goto end;
|
|
}
|
|
|
|
if (case_range < 0)
|
|
nickname3 = strdup (nickname2);
|
|
else if (case_range == 0)
|
|
nickname3 = string_tolower (nickname2);
|
|
else
|
|
nickname3 = string_tolower_range (nickname2, case_range);
|
|
if (!nickname3)
|
|
goto end;
|
|
|
|
/* hash nickname to get color */
|
|
color = gui_nick_hash_color (
|
|
nickname3,
|
|
(list_colors) ? num_colors : config_num_nick_colors);
|
|
ptr_result = (list_colors) ?
|
|
list_colors[color] : config_nick_colors[color];
|
|
|
|
end:
|
|
result = strdup ((ptr_result) ? ptr_result : default_color);
|
|
string_free_split (list_colors);
|
|
free (nickname2);
|
|
free (nickname3);
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* Finds a color code for a nick (according to nick letters).
|
|
*
|
|
* If case_range < 0, nick is case-sensitive.
|
|
* If case_range == 0, nick is converted to lower case (with string_tolower).
|
|
* If case_range > 0, nick is converted to lower case (with string_tolower_range).
|
|
*
|
|
* If colors is NULL (most common case), the color returned is either a forced
|
|
* color (from option "weechat.look.nick_color_force") or a color from option
|
|
* "weechat.color.chat_nick_colors".
|
|
*
|
|
* If colors is set and not empty, a color from this list is returned
|
|
* (format of argument: comma-separated list of colors, a background is
|
|
* allowed with format "fg:bg", for example: "blue,yellow:red" for blue and
|
|
* yellow on red).
|
|
*
|
|
* Returns a WeeChat color code (that can be used for display).
|
|
*
|
|
* Note: result must be freed after use.
|
|
*/
|
|
|
|
char *
|
|
gui_nick_find_color (const char *nickname, int case_range, const char *colors)
|
|
{
|
|
char *color;
|
|
const char *ptr_result;
|
|
|
|
color = gui_nick_find_color_name (nickname, case_range, colors);
|
|
ptr_result = gui_color_get_custom (color);
|
|
free (color);
|
|
return (ptr_result) ? strdup (ptr_result) : NULL;
|
|
}
|