Replace utf8codepoint with Chris Wellons' utf8_decode
Code under a different license should be kept in a separate file. This implemention is a single header file with ~65 lines, so it better fits this requirement.
This commit is contained in:
		
							
								
								
									
										1
									
								
								sxiv.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								sxiv.h
									
									
									
									
									
								
							@@ -361,7 +361,6 @@ int r_opendir(r_dir_t*, const char*, bool);
 | 
			
		||||
int r_closedir(r_dir_t*);
 | 
			
		||||
char* r_readdir(r_dir_t*);
 | 
			
		||||
int r_mkdir(char*);
 | 
			
		||||
void* utf8codepoint(const void * __restrict__ str, long * __restrict__ out_codepoint);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* window.c */
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										68
									
								
								utf8.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								utf8.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,68 @@
 | 
			
		||||
/* Branchless UTF-8 decoder
 | 
			
		||||
 *
 | 
			
		||||
 * This is free and unencumbered software released into the public domain.
 | 
			
		||||
 */
 | 
			
		||||
#ifndef UTF8_H
 | 
			
		||||
#define UTF8_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/* Decode the next character, C, from BUF, reporting errors in E.
 | 
			
		||||
 *
 | 
			
		||||
 * Since this is a branchless decoder, four bytes will be read from the
 | 
			
		||||
 * buffer regardless of the actual length of the next character. This
 | 
			
		||||
 * means the buffer _must_ have at least three bytes of zero padding
 | 
			
		||||
 * following the end of the data stream.
 | 
			
		||||
 *
 | 
			
		||||
 * Errors are reported in E, which will be non-zero if the parsed
 | 
			
		||||
 * character was somehow invalid: invalid byte sequence, non-canonical
 | 
			
		||||
 * encoding, or a surrogate half.
 | 
			
		||||
 *
 | 
			
		||||
 * The function returns a pointer to the next character. When an error
 | 
			
		||||
 * occurs, this pointer will be a guess that depends on the particular
 | 
			
		||||
 * error, but it will always advance at least one byte.
 | 
			
		||||
 */
 | 
			
		||||
static void *
 | 
			
		||||
utf8_decode(void *buf, uint32_t *c, int *e)
 | 
			
		||||
{
 | 
			
		||||
    static const char lengths[] = {
 | 
			
		||||
        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 | 
			
		||||
        0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0
 | 
			
		||||
    };
 | 
			
		||||
    static const int masks[]  = {0x00, 0x7f, 0x1f, 0x0f, 0x07};
 | 
			
		||||
    static const uint32_t mins[] = {4194304, 0, 128, 2048, 65536};
 | 
			
		||||
    static const int shiftc[] = {0, 18, 12, 6, 0};
 | 
			
		||||
    static const int shifte[] = {0, 6, 4, 2, 0};
 | 
			
		||||
 | 
			
		||||
    unsigned char *s = buf;
 | 
			
		||||
    int len = lengths[s[0] >> 3];
 | 
			
		||||
 | 
			
		||||
    /* Compute the pointer to the next character early so that the next
 | 
			
		||||
     * iteration can start working on the next character. Neither Clang
 | 
			
		||||
     * nor GCC figure out this reordering on their own.
 | 
			
		||||
     */
 | 
			
		||||
    unsigned char *next = s + len + !len;
 | 
			
		||||
 | 
			
		||||
    /* Assume a four-byte character and load four bytes. Unused bits are
 | 
			
		||||
     * shifted out.
 | 
			
		||||
     */
 | 
			
		||||
    *c  = (uint32_t)(s[0] & masks[len]) << 18;
 | 
			
		||||
    *c |= (uint32_t)(s[1] & 0x3f) << 12;
 | 
			
		||||
    *c |= (uint32_t)(s[2] & 0x3f) <<  6;
 | 
			
		||||
    *c |= (uint32_t)(s[3] & 0x3f) <<  0;
 | 
			
		||||
    *c >>= shiftc[len];
 | 
			
		||||
 | 
			
		||||
    /* Accumulate the various error conditions. */
 | 
			
		||||
    *e  = (*c < mins[len]) << 6; // non-canonical encoding
 | 
			
		||||
    *e |= ((*c >> 11) == 0x1b) << 7;  // surrogate half?
 | 
			
		||||
    *e |= (*c > 0x10FFFF) << 8;  // out of range?
 | 
			
		||||
    *e |= (s[1] & 0xc0) >> 2;
 | 
			
		||||
    *e |= (s[2] & 0xc0) >> 4;
 | 
			
		||||
    *e |= (s[3]       ) >> 6;
 | 
			
		||||
    *e ^= 0x2a; // top two bits of each tail byte correct?
 | 
			
		||||
    *e >>= shifte[len];
 | 
			
		||||
 | 
			
		||||
    return next;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										28
									
								
								util.c
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								util.c
									
									
									
									
									
								
							@@ -205,31 +205,3 @@ int r_mkdir(char *path)
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* copied from sheredom's utf8.h (public domain) https://github.com/sheredom/utf8.h */
 | 
			
		||||
 | 
			
		||||
void* utf8codepoint(const void* __restrict__ str, long* __restrict__ out_codepoint)
 | 
			
		||||
{
 | 
			
		||||
	 const char *s = (const char *)str;
 | 
			
		||||
 | 
			
		||||
	 if (0xf0 == (0xf8 & s[0])) {
 | 
			
		||||
		// 4 byte utf8 codepoint
 | 
			
		||||
		*out_codepoint = ((0x07 & s[0]) << 18) | ((0x3f & s[1]) << 12) |
 | 
			
		||||
				 ((0x3f & s[2]) << 6) | (0x3f & s[3]);
 | 
			
		||||
		s += 4;
 | 
			
		||||
	} else if (0xe0 == (0xf0 & s[0])) {
 | 
			
		||||
		// 3 byte utf8 codepoint
 | 
			
		||||
		*out_codepoint = ((0x0f & s[0]) << 12) | ((0x3f & s[1]) << 6) | (0x3f & s[2]);
 | 
			
		||||
		s += 3;
 | 
			
		||||
	} else if (0xc0 == (0xe0 & s[0])) {
 | 
			
		||||
		// 2 byte utf8 codepoint
 | 
			
		||||
		*out_codepoint = ((0x1f & s[0]) << 6) | (0x3f & s[1]);
 | 
			
		||||
		s += 2;
 | 
			
		||||
	} else {
 | 
			
		||||
		// 1 byte utf8 codepoint otherwise
 | 
			
		||||
		*out_codepoint = s[0];
 | 
			
		||||
		s += 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (void *)s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										12
									
								
								window.c
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								window.c
									
									
									
									
									
								
							@@ -20,6 +20,7 @@
 | 
			
		||||
#define _WINDOW_CONFIG
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "icon/data.h"
 | 
			
		||||
#include "utf8.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
@@ -131,8 +132,9 @@ void win_init(win_t *win)
 | 
			
		||||
 | 
			
		||||
	win->bar.l.size = BAR_L_LEN;
 | 
			
		||||
	win->bar.r.size = BAR_R_LEN;
 | 
			
		||||
	win->bar.l.buf = emalloc(win->bar.l.size);
 | 
			
		||||
	win->bar.r.buf = emalloc(win->bar.r.size);
 | 
			
		||||
	/* 3 padding bytes needed by utf8_decode */
 | 
			
		||||
	win->bar.l.buf = emalloc(win->bar.l.size + 3);
 | 
			
		||||
	win->bar.r.buf = emalloc(win->bar.r.size + 3);
 | 
			
		||||
	win->bar.h = options->hide_bar ? 0 : barheight;
 | 
			
		||||
 | 
			
		||||
	INIT_ATOM_(WM_DELETE_WINDOW);
 | 
			
		||||
@@ -371,14 +373,14 @@ int win_textwidth(const win_env_t *e, const char *text, unsigned int len, bool w
 | 
			
		||||
void win_draw_bar_text(win_t *win, XftDraw *d, XftColor *color, XftFont *font, int x, int y, char *text, int maxlen, int maximum_x)
 | 
			
		||||
{
 | 
			
		||||
	size_t len = 0;
 | 
			
		||||
	int xshift = 0, newshift;
 | 
			
		||||
	long codep;
 | 
			
		||||
	int err, xshift = 0, newshift;
 | 
			
		||||
	uint32_t codep;
 | 
			
		||||
	char *p, *nextp;
 | 
			
		||||
	FcCharSet* fccharset;
 | 
			
		||||
	XftFont* fallback = NULL;
 | 
			
		||||
 | 
			
		||||
	for (p = text; *p && (len < maxlen); p = nextp, len++) {
 | 
			
		||||
		nextp = utf8codepoint(p, &codep);
 | 
			
		||||
		nextp = utf8_decode(p, &codep, &err);
 | 
			
		||||
		if (!XftCharExists(win->env.dpy, font, codep)) {
 | 
			
		||||
			fccharset = FcCharSetCreate();
 | 
			
		||||
			FcCharSetAddChar(fccharset, codep);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user