mirror of
				https://github.com/tmux/tmux.git
				synced 2025-11-04 00:56:10 +00:00 
			
		
		
		
	Add some UTF-8 utility functions and use them to prevent the width limit
on formats from splitting UTF-8 characters improperly.
This commit is contained in:
		
							
								
								
									
										13
									
								
								format.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								format.c
									
									
									
									
									
								
							@@ -194,10 +194,10 @@ int
 | 
				
			|||||||
format_replace(struct format_tree *ft, const char *key, size_t keylen,
 | 
					format_replace(struct format_tree *ft, const char *key, size_t keylen,
 | 
				
			||||||
    char **buf, size_t *len, size_t *off)
 | 
					    char **buf, size_t *len, size_t *off)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char		*copy, *copy0, *endptr, *ptr, *saved;
 | 
						char		*copy, *copy0, *endptr, *ptr, *saved, *trimmed;
 | 
				
			||||||
	const char	*value;
 | 
						const char	*value;
 | 
				
			||||||
	size_t		 valuelen;
 | 
						size_t		 valuelen;
 | 
				
			||||||
	u_long		 limit = ULONG_MAX;
 | 
						u_long		 limit = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Make a copy of the key. */
 | 
						/* Make a copy of the key. */
 | 
				
			||||||
	copy0 = copy = xmalloc(keylen + 1);
 | 
						copy0 = copy = xmalloc(keylen + 1);
 | 
				
			||||||
@@ -256,11 +256,14 @@ format_replace(struct format_tree *ft, const char *key, size_t keylen,
 | 
				
			|||||||
			value = "";
 | 
								value = "";
 | 
				
			||||||
		saved = NULL;
 | 
							saved = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	valuelen = strlen(value);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Truncate the value if needed. */
 | 
						/* Truncate the value if needed. */
 | 
				
			||||||
	if (valuelen > limit)
 | 
						if (limit != 0) {
 | 
				
			||||||
		valuelen = limit;
 | 
							value = trimmed = utf8_trimcstr(value, limit);
 | 
				
			||||||
 | 
							free(saved);
 | 
				
			||||||
 | 
							saved = trimmed;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						valuelen = strlen(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Expand the buffer and copy in the value. */
 | 
						/* Expand the buffer and copy in the value. */
 | 
				
			||||||
	while (*len - *off < valuelen + 1) {
 | 
						while (*len - *off < valuelen + 1) {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								tmux.h
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								tmux.h
									
									
									
									
									
								
							@@ -2306,7 +2306,7 @@ struct winlink	*session_new(struct session *, const char *, const char *,
 | 
				
			|||||||
struct winlink	*session_attach(
 | 
					struct winlink	*session_attach(
 | 
				
			||||||
		     struct session *, struct window *, int, char **);
 | 
							     struct session *, struct window *, int, char **);
 | 
				
			||||||
int		 session_detach(struct session *, struct winlink *);
 | 
					int		 session_detach(struct session *, struct winlink *);
 | 
				
			||||||
struct winlink*	 session_has(struct session *, struct window *);
 | 
					struct winlink	*session_has(struct session *, struct window *);
 | 
				
			||||||
int		 session_next(struct session *, int);
 | 
					int		 session_next(struct session *, int);
 | 
				
			||||||
int		 session_previous(struct session *, int);
 | 
					int		 session_previous(struct session *, int);
 | 
				
			||||||
int		 session_select(struct session *, int);
 | 
					int		 session_select(struct session *, int);
 | 
				
			||||||
@@ -2322,12 +2322,17 @@ void		 session_group_synchronize1(struct session *, struct session *);
 | 
				
			|||||||
void		 session_renumber_windows(struct session *);
 | 
					void		 session_renumber_windows(struct session *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* utf8.c */
 | 
					/* utf8.c */
 | 
				
			||||||
void	utf8_build(void);
 | 
					void		 utf8_build(void);
 | 
				
			||||||
int	utf8_open(struct utf8_data *, u_char);
 | 
					void		 utf8_set(struct utf8_data *, u_char);
 | 
				
			||||||
int	utf8_append(struct utf8_data *, u_char);
 | 
					int		 utf8_open(struct utf8_data *, u_char);
 | 
				
			||||||
u_int	utf8_combine(const struct utf8_data *);
 | 
					int		 utf8_append(struct utf8_data *, u_char);
 | 
				
			||||||
u_int	utf8_split2(u_int, u_char *);
 | 
					u_int		 utf8_combine(const struct utf8_data *);
 | 
				
			||||||
int	utf8_strvis(char *, const char *, size_t, int);
 | 
					u_int		 utf8_split2(u_int, u_char *);
 | 
				
			||||||
 | 
					int		 utf8_strvis(char *, const char *, size_t, int);
 | 
				
			||||||
 | 
					struct utf8_data *utf8_fromcstr(const char *);
 | 
				
			||||||
 | 
					char		*utf8_tocstr(struct utf8_data *);
 | 
				
			||||||
 | 
					u_int		 utf8_cstrwidth(const char *);
 | 
				
			||||||
 | 
					char		*utf8_trimcstr(const char *, u_int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* procname.c */
 | 
					/* procname.c */
 | 
				
			||||||
char   *get_proc_name(int, char *);
 | 
					char   *get_proc_name(int, char *);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										119
									
								
								utf8.c
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								utf8.c
									
									
									
									
									
								
							@@ -18,6 +18,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
#include <vis.h>
 | 
					#include <vis.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -199,6 +200,16 @@ int	utf8_overlap(struct utf8_width_entry *, struct utf8_width_entry *);
 | 
				
			|||||||
u_int	utf8_combine(const struct utf8_data *);
 | 
					u_int	utf8_combine(const struct utf8_data *);
 | 
				
			||||||
u_int	utf8_width(const struct utf8_data *);
 | 
					u_int	utf8_width(const struct utf8_data *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Set a single character. */
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					utf8_set(struct utf8_data *utf8data, u_char ch)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						*utf8data->data = ch;
 | 
				
			||||||
 | 
						utf8data->size = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						utf8data->width = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Open UTF-8 sequence.
 | 
					 * Open UTF-8 sequence.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -392,3 +403,111 @@ utf8_strvis(char *dst, const char *src, size_t len, int flag)
 | 
				
			|||||||
	*dst = '\0';
 | 
						*dst = '\0';
 | 
				
			||||||
	return (dst - start);
 | 
						return (dst - start);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Convert a string into a buffer of UTF-8 characters. Terminated by size == 0.
 | 
				
			||||||
 | 
					 * Caller frees.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct utf8_data *
 | 
				
			||||||
 | 
					utf8_fromcstr(const char *src)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct utf8_data	*dst;
 | 
				
			||||||
 | 
						size_t			 n;
 | 
				
			||||||
 | 
						int			 more;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dst = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n = 0;
 | 
				
			||||||
 | 
						while (*src != '\0') {
 | 
				
			||||||
 | 
							dst = xrealloc(dst, n + 1, sizeof *dst);
 | 
				
			||||||
 | 
							if (utf8_open(&dst[n], *src)) {
 | 
				
			||||||
 | 
								more = 1;
 | 
				
			||||||
 | 
								while (*++src != '\0' && more)
 | 
				
			||||||
 | 
									more = utf8_append(&dst[n], *src);
 | 
				
			||||||
 | 
								if (!more) {
 | 
				
			||||||
 | 
									n++;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								src -= dst[n].have;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							utf8_set(&dst[n], *src);
 | 
				
			||||||
 | 
							src++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							n++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dst = xrealloc(dst, n + 1, sizeof *dst);
 | 
				
			||||||
 | 
						dst[n].size = 0;
 | 
				
			||||||
 | 
						return (dst);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Convert from a buffer of UTF-8 characters into a string. Caller frees. */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					utf8_tocstr(struct utf8_data *src)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char	*dst;
 | 
				
			||||||
 | 
						size_t	 n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dst = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						n = 0;
 | 
				
			||||||
 | 
						for(; src->size != 0; src++) {
 | 
				
			||||||
 | 
							dst = xrealloc(dst, n + src->size, 1);
 | 
				
			||||||
 | 
							memcpy(dst + n, src->data, src->size);
 | 
				
			||||||
 | 
							n += src->size;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dst = xrealloc(dst, n + 1, 1);
 | 
				
			||||||
 | 
						dst[n] = '\0';
 | 
				
			||||||
 | 
						return (dst);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Get width of UTF-8 string. */
 | 
				
			||||||
 | 
					u_int
 | 
				
			||||||
 | 
					utf8_cstrwidth(const char *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct utf8_data	tmp;
 | 
				
			||||||
 | 
						u_int			width;
 | 
				
			||||||
 | 
						int			more;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						width = 0;
 | 
				
			||||||
 | 
						while (*s != '\0') {
 | 
				
			||||||
 | 
							if (utf8_open(&tmp, *s)) {
 | 
				
			||||||
 | 
								more = 1;
 | 
				
			||||||
 | 
								while (*++s != '\0' && more)
 | 
				
			||||||
 | 
									more = utf8_append(&tmp, *s);
 | 
				
			||||||
 | 
								if (!more) {
 | 
				
			||||||
 | 
									width += tmp.width;
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								s -= tmp.have;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							width++;
 | 
				
			||||||
 | 
							s++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return (width);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Trim UTF-8 string to width. Caller frees. */
 | 
				
			||||||
 | 
					char *
 | 
				
			||||||
 | 
					utf8_trimcstr(const char *s, u_int width)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct utf8_data	*tmp, *next;
 | 
				
			||||||
 | 
						char			*out;
 | 
				
			||||||
 | 
						u_int			 at;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tmp = utf8_fromcstr(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						at = 0;
 | 
				
			||||||
 | 
						for (next = tmp; next->size != 0; next++) {
 | 
				
			||||||
 | 
							if (at + next->width > width) {
 | 
				
			||||||
 | 
								next->size = 0;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							at += next->width;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out = utf8_tocstr(tmp);
 | 
				
			||||||
 | 
						free(tmp);
 | 
				
			||||||
 | 
						return (out);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user