sled

Једноставни уређивач текста
git clone https://git.sr.ht/~strahinja/sled
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

util.c (4979B)


      1 /* This program is licensed under the terms of GNU GPL v3 or (at your option)
      2  * any later version. Copyright (C) 2022-2026  Страхиња Радић.
      3  * See the file LICENSE for exact copyright and license details. */
      4 #include <assert.h>
      5 #include <stdarg.h>
      6 #include <stddef.h>
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 
     11 #include "limit.h"
     12 #include "termbox.h"
     13 #include "util.h"
     14 
     15 /* Whitespace definition for determining word boundaries */
     16 #define B_WS " \v\t"
     17 /* Full word boundary delimiter definition */
     18 #define B_FULL " \v\t()[]{},.;:/\\"
     19 
     20 size_t
     21 u8_string_to_unicode(uint32_t* us, const char* s, const ssize_t max)
     22 {
     23 	uint32_t uch;
     24 	uint32_t* pus  = us;
     25 	const char* ps = s;
     26 	int u8_len     = 0;
     27 	size_t added   = 0;
     28 
     29 	assert(s != NULL);
     30 	while (ps - s < max && *ps)
     31 	{
     32 		u8_len = tb_utf8_char_to_unicode(&uch, ps);
     33 		if (!u8_len)
     34 		{
     35 			uch    = U32_REPL_CHAR;
     36 			u8_len = 1;
     37 		}
     38 		added++;
     39 		ps += u8_len;
     40 		*pus++ = uch;
     41 	}
     42 	*pus = 0;
     43 	return added;
     44 }
     45 
     46 size_t
     47 unicode_string_to_u8(char* s, const uint32_t* us, const ssize_t max)
     48 {
     49 	char ch[8];
     50 	char* ps	    = NULL;
     51 	const uint32_t* pus = us;
     52 	size_t len;
     53 	size_t added = 0;
     54 
     55 	assert((s != NULL) && (us != NULL));
     56 	ps = s;
     57 	while (pus - us < max && *pus)
     58 	{
     59 		len = tb_utf8_unicode_to_char(ch, *pus);
     60 		if (len < 0)
     61 			return added;
     62 		memccpy(ps, ch, 0, len);
     63 		ps += len;
     64 		added++;
     65 		pus++;
     66 	}
     67 	*ps = 0;
     68 	return added;
     69 }
     70 
     71 int
     72 u32_has_nonblanks(const uint32_t* s)
     73 {
     74 	const uint32_t* ps = s;
     75 
     76 	assert(s != NULL);
     77 	while (*ps)
     78 	{
     79 		if (!u32_is_word_boundary(*ps, 1))
     80 			return 1;
     81 		ps++;
     82 	}
     83 	return 0;
     84 }
     85 
     86 uint32_t*
     87 u32_memccpy(uint32_t* dst, const uint32_t* src, uint32_t c, size_t len)
     88 {
     89 	size_t copied = 0;
     90 	assert((dst != NULL) && (src != NULL));
     91 	while ((*dst++ = *src++) != c && copied < len)
     92 		copied++;
     93 	if (copied == len)
     94 		return NULL;
     95 	return dst;
     96 }
     97 
     98 /* len is the max length of src in bytes */
     99 uint32_t*
    100 u32_u8_memccpy(uint32_t* dst, const char* src, uint32_t c, size_t len)
    101 {
    102 	const char* psrc = src;
    103 	uint32_t uch;
    104 	size_t copied = 0;
    105 	int u8_len;
    106 
    107 	assert((dst != NULL) && (src != NULL));
    108 	do
    109 	{
    110 		if (!*psrc)
    111 		{
    112 			*dst++ = 0;
    113 			break;
    114 		}
    115 		u8_len = tb_utf8_char_to_unicode(&uch, psrc);
    116 		if (u8_len < 0)
    117 		{
    118 			/* error, replace uch with "error char" */
    119 			uch    = 0xFFFD;
    120 			u8_len = -u8_len;
    121 		}
    122 		psrc += u8_len;
    123 		copied += u8_len;
    124 		if (copied >= len)
    125 			return NULL;
    126 	} while ((*dst++ = uch) != c && copied < len);
    127 	return dst;
    128 }
    129 
    130 size_t
    131 u8_strlen(const char* s)
    132 {
    133 	const char* ps = s;
    134 	uint32_t uc;
    135 	size_t len;
    136 	size_t result = 0;
    137 	assert(s != NULL);
    138 	while (*ps)
    139 	{
    140 		len = tb_utf8_char_to_unicode(&uc, ps);
    141 		result += len;
    142 		ps++;
    143 	}
    144 	return result;
    145 }
    146 
    147 size_t
    148 u32_strlen(const uint32_t* s)
    149 {
    150 	const uint32_t* ps = s;
    151 	size_t len	   = 0;
    152 	assert(s != NULL);
    153 	while (*ps++)
    154 		len++;
    155 	return len;
    156 }
    157 
    158 const uint32_t*
    159 u32_strstr(const uint32_t* haystack, const uint32_t* needle)
    160 {
    161 	const uint32_t* ph = haystack;
    162 	assert((haystack != NULL) && (needle != NULL));
    163 	while (*ph)
    164 	{
    165 		if (u32_starts_with(ph, needle))
    166 			return ph;
    167 		ph++;
    168 	}
    169 	return NULL;
    170 }
    171 
    172 const uint32_t*
    173 u32_strrstr(const uint32_t* haystack, const uint32_t* needle,
    174 	const uint32_t* haystack_tail)
    175 {
    176 	size_t needle_len = u32_strlen(needle);
    177 	const uint32_t* ph;
    178 
    179 	assert((haystack != NULL) && (haystack_tail != NULL)
    180 		&& (needle != NULL));
    181 	if (needle_len > (size_t)(haystack_tail - haystack))
    182 		return NULL;
    183 
    184 	ph = haystack_tail - needle_len;
    185 
    186 strrstr_loop:
    187 	if (u32_starts_with(ph, needle))
    188 		return ph;
    189 	if (ph != haystack)
    190 		ph--;
    191 	else
    192 		goto strrstr_end;
    193 	goto strrstr_loop;
    194 strrstr_end:
    195 	return NULL;
    196 }
    197 
    198 const uint32_t*
    199 u32_strchr(const uint32_t* haystack, const uint32_t needle)
    200 {
    201 	const uint32_t* ph = haystack;
    202 	assert(haystack != NULL);
    203 	while (*ph)
    204 	{
    205 		if (*ph == needle)
    206 			return ph;
    207 		ph++;
    208 	}
    209 	return NULL;
    210 }
    211 
    212 int
    213 is_word_boundary(const char ch, const int strictly_whitespace)
    214 {
    215 	return strictly_whitespace ? strchr(B_WS, ch) != NULL
    216 				   : strchr(B_FULL, ch) != NULL;
    217 }
    218 
    219 int
    220 u32_is_word_boundary(const uint32_t ch, const int strictly_whitespace)
    221 {
    222 	static uint32_t uws[sizeof(B_WS) + 1];
    223 	static uint32_t ufull[sizeof(B_FULL) + 1];
    224 	if (!*uws)
    225 	{
    226 		(void)u8_string_to_unicode(uws, B_WS, sizeof(B_WS));
    227 		(void)u8_string_to_unicode(ufull, B_FULL, sizeof(B_FULL));
    228 	}
    229 	return strictly_whitespace ? u32_strchr(uws, ch) != NULL
    230 				   : u32_strchr(ufull, ch) != NULL;
    231 }
    232 
    233 int
    234 starts_with(const char* s, const char* with)
    235 {
    236 	assert((s != NULL) && (with != NULL));
    237 	while (*s && *s == *with)
    238 	{
    239 		if (*s != *with)
    240 			return 0;
    241 		s++;
    242 		with++;
    243 	}
    244 	return *with == 0;
    245 }
    246 
    247 int
    248 u32_starts_with(const uint32_t* s, const uint32_t* with)
    249 {
    250 	assert((s != NULL) && (with != NULL));
    251 	while (*s && *s == *with)
    252 	{
    253 		if (*s != *with)
    254 			return 0;
    255 		s++;
    256 		with++;
    257 	}
    258 	return *with == 0;
    259 }
    260 
    261 const char*
    262 u8_basename(const char* path)
    263 {
    264 	const char* ppath;
    265 	assert(path != NULL);
    266 	ppath = path + strlen(path);
    267 	while (ppath != path && *ppath != '/')
    268 		ppath--;
    269 	if (*ppath == '/')
    270 		ppath++;
    271 	return ppath;
    272 }