remove gcc for MacOS in conan.yml
[liba.git] / lua / isocline / src / common.c
blob4cf8b57fff1e650de21c501e04c58e0228c8368d
1 /* ----------------------------------------------------------------------------
2 Copyright (c) 2021, Daan Leijen
3 This is free software; you can redistribute it and/or modify it
4 under the terms of the MIT License. A copy of the license can be
5 found in the "LICENSE" file at the root of this distribution.
6 -----------------------------------------------------------------------------*/
8 #include <string.h>
9 #include <stdio.h>
10 #include <stdarg.h>
11 #include <stdlib.h>
12 #include "common.h"
15 //-------------------------------------------------------------
16 // String wrappers for ssize_t
17 //-------------------------------------------------------------
19 ic_private ssize_t ic_strlen( const char* s ) {
20 if (s == NULL) { return 0; }
21 return to_ssize_t(strlen(s));
24 ic_private void ic_memmove( void* dest, const void* src, ssize_t n ) {
25 assert(dest != NULL && src != NULL);
26 if (n <= 0) { return; }
27 memmove(dest,src,to_size_t(n));
31 ic_private void ic_memcpy( void* dest, const void* src, ssize_t n ) {
32 assert(dest != NULL && src != NULL);
33 if (dest == NULL || src == NULL || n <= 0) { return; }
34 memcpy(dest,src,to_size_t(n));
37 ic_private void ic_memset(void* dest, uint8_t value, ssize_t n) {
38 assert(dest != NULL);
39 if (dest == NULL || n <= 0) { return; }
40 memset(dest,(int8_t)value,to_size_t(n));
43 ic_private bool ic_memnmove( void* dest, ssize_t dest_size, const void* src, ssize_t n ) {
44 assert(dest != NULL && src != NULL);
45 if (n <= 0) { return true; }
46 if (dest_size < n) { assert(false); return false; }
47 memmove(dest,src,to_size_t(n));
48 return true;
51 ic_private bool ic_strcpy( char* dest, ssize_t dest_size /* including 0 */, const char* src) {
52 assert(dest != NULL && src != NULL);
53 if (dest == NULL || dest_size <= 0) { return false; }
54 ssize_t slen = ic_strlen(src);
55 if (slen >= dest_size) { return false; }
56 strcpy(dest,src);
57 assert(dest[slen] == 0);
58 return true;
62 ic_private bool ic_strncpy( char* dest, ssize_t dest_size /* including 0 */, const char* src, ssize_t n) {
63 assert(dest != NULL && n < dest_size);
64 if (dest == NULL || dest_size <= 0) { return false; }
65 if (n >= dest_size) { return false; }
66 if (src == NULL || n <= 0) {
67 dest[0] = 0;
69 else {
70 strncpy(dest,src,to_size_t(n));
71 dest[n] = 0;
73 return true;
76 //-------------------------------------------------------------
77 // String matching
78 //-------------------------------------------------------------
80 ic_public bool ic_starts_with( const char* s, const char* prefix ) {
81 if (s == prefix) { return true; }
82 if (prefix == NULL) { return true; }
83 if (s == NULL) { return false; }
85 ssize_t i;
86 for( i = 0; s[i] != 0 && prefix[i] != 0; i++) {
87 if (s[i] != prefix[i]) { return false; }
89 return (prefix[i] == 0);
92 ic_private char ic_tolower( char c ) {
93 return (c >= 'A' && c <= 'Z' ? c - 'A' + 'a' : c);
96 ic_private void ic_str_tolower(char* s) {
97 while(*s != 0) {
98 *s = ic_tolower(*s);
99 s++;
103 ic_public bool ic_istarts_with( const char* s, const char* prefix ) {
104 if (s == prefix) { return true; }
105 if (prefix == NULL) { return true; }
106 if (s == NULL) { return false; }
108 ssize_t i;
109 for( i = 0; s[i] != 0 && prefix[i] != 0; i++) {
110 if (ic_tolower(s[i]) != ic_tolower(prefix[i])) { return false; }
112 return (prefix[i] == 0);
116 ic_private int ic_strnicmp(const char* s1, const char* s2, ssize_t n) {
117 if (s1 == NULL && s2 == NULL) { return 0; }
118 if (s1 == NULL) { return -1; }
119 if (s2 == NULL) { return 1; }
120 ssize_t i;
121 for (i = 0; s1[i] != 0 && i < n; i++) { // note: if s2[i] == 0 the loop will stop as c1 != c2
122 char c1 = ic_tolower(s1[i]);
123 char c2 = ic_tolower(s2[i]);
124 if (c1 < c2) { return -1; }
125 if (c1 > c2) { return 1; }
127 return ((i >= n || s2[i] == 0) ? 0 : -1);
130 ic_private int ic_stricmp(const char* s1, const char* s2) {
131 ssize_t len1 = ic_strlen(s1);
132 ssize_t len2 = ic_strlen(s2);
133 if (len1 < len2) { return -1; }
134 if (len1 > len2) { return 1; }
135 return (ic_strnicmp(s1, s2, (len1 >= len2 ? len1 : len2)));
139 static const char* ic_stristr(const char* s, const char* pat) {
140 if (s == NULL) { return NULL; }
141 if (pat == NULL || pat[0] == 0) { return s; }
142 ssize_t patlen = ic_strlen(pat);
143 for (ssize_t i = 0; s[i] != 0; i++) {
144 if (ic_strnicmp(s + i, pat, patlen) == 0) { return (s+i); }
146 return NULL;
149 ic_private bool ic_contains(const char* big, const char* s) {
150 if (big == NULL) { return false; }
151 if (s == NULL) { return true; }
152 return (strstr(big,s) != NULL);
155 ic_private bool ic_icontains(const char* big, const char* s) {
156 if (big == NULL) { return false; }
157 if (s == NULL) { return true; }
158 return (ic_stristr(big,s) != NULL);
162 //-------------------------------------------------------------
163 // Unicode
164 // QUTF-8: See <https://github.com/koka-lang/koka/blob/master/kklib/include/kklib/string.h>
165 // Raw bytes are code points 0xEE000 - 0xEE0FF
166 //-------------------------------------------------------------
167 #define IC_UNICODE_RAW ((unicode_t)(0xEE000U))
169 ic_private unicode_t unicode_from_raw(uint8_t c) {
170 return (IC_UNICODE_RAW + c);
173 ic_private bool unicode_is_raw(unicode_t u, uint8_t* c) {
174 if (u >= IC_UNICODE_RAW && u <= IC_UNICODE_RAW + 0xFF) {
175 *c = (uint8_t)(u - IC_UNICODE_RAW);
176 return true;
178 else {
179 return false;
183 ic_private void unicode_to_qutf8(unicode_t u, uint8_t buf[5]) {
184 memset(buf, 0, 5);
185 if (u <= 0x7F) {
186 buf[0] = (uint8_t)u;
188 else if (u <= 0x07FF) {
189 buf[0] = (0xC0 | ((uint8_t)(u >> 6)));
190 buf[1] = (0x80 | (((uint8_t)u) & 0x3F));
192 else if (u <= 0xFFFF) {
193 buf[0] = (0xE0 | ((uint8_t)(u >> 12)));
194 buf[1] = (0x80 | (((uint8_t)(u >> 6)) & 0x3F));
195 buf[2] = (0x80 | (((uint8_t)u) & 0x3F));
197 else if (u <= 0x10FFFF) {
198 if (unicode_is_raw(u, &buf[0])) {
199 buf[1] = 0;
201 else {
202 buf[0] = (0xF0 | ((uint8_t)(u >> 18)));
203 buf[1] = (0x80 | (((uint8_t)(u >> 12)) & 0x3F));
204 buf[2] = (0x80 | (((uint8_t)(u >> 6)) & 0x3F));
205 buf[3] = (0x80 | (((uint8_t)u) & 0x3F));
210 // is this a utf8 continuation byte?
211 ic_private bool utf8_is_cont(uint8_t c) {
212 return ((c & 0xC0) == 0x80);
215 ic_private unicode_t unicode_from_qutf8(const uint8_t* s, ssize_t len, ssize_t* count) {
216 unicode_t c0 = 0;
217 if (len <= 0 || s == NULL) {
218 goto fail;
220 // 1 byte
221 c0 = s[0];
222 if (c0 <= 0x7F && len >= 1) {
223 if (count != NULL) { *count = 1; }
224 return c0;
226 else if (c0 <= 0xC1) { // invalid continuation byte or invalid 0xC0, 0xC1
227 goto fail;
229 // 2 bytes
230 else if (c0 <= 0xDF && len >= 2 && utf8_is_cont(s[1])) {
231 if (count != NULL) { *count = 2; }
232 return (((c0 & 0x1F) << 6) | (s[1] & 0x3F));
234 // 3 bytes: reject overlong and surrogate halves
235 else if (len >= 3 &&
236 ((c0 == 0xE0 && s[1] >= 0xA0 && s[1] <= 0xBF && utf8_is_cont(s[2])) ||
237 (c0 >= 0xE1 && c0 <= 0xEF && c0 != 0xED && utf8_is_cont(s[1]) && utf8_is_cont(s[2])) ||
238 (c0 == 0xED && s[1] > 0x80 && s[1] <= 0x9F && utf8_is_cont(s[2]))
241 if (count != NULL) { *count = 3; }
242 return (((c0 & 0x0F) << 12) | ((unicode_t)(s[1] & 0x3F) << 6) | (s[2] & 0x3F));
244 // 4 bytes: reject overlong
245 else if (len >= 4 &&
246 (((c0 == 0xF0 && s[1] >= 0x90 && s[1] <= 0xBF && utf8_is_cont(s[2]) && utf8_is_cont(s[3])) ||
247 (c0 >= 0xF1 && c0 <= 0xF3 && utf8_is_cont(s[1]) && utf8_is_cont(s[2]) && utf8_is_cont(s[3])) ||
248 (c0 == 0xF4 && s[1] >= 0x80 && s[1] <= 0x8F && utf8_is_cont(s[2]) && utf8_is_cont(s[3])))
251 if (count != NULL) { *count = 4; }
252 return (((c0 & 0x07) << 18) | ((unicode_t)(s[1] & 0x3F) << 12) | ((unicode_t)(s[2] & 0x3F) << 6) | (s[3] & 0x3F));
254 fail:
255 if (count != NULL) { *count = 1; }
256 return unicode_from_raw(s[0]);
260 //-------------------------------------------------------------
261 // Debug
262 //-------------------------------------------------------------
264 #if defined(IC_NO_DEBUG_MSG)
265 // nothing
266 #elif !defined(IC_DEBUG_TO_FILE)
267 ic_private void debug_msg(const char* fmt, ...) {
268 if (getenv("ISOCLINE_DEBUG")) {
269 va_list args;
270 va_start(args, fmt);
271 vfprintf(stderr, fmt, args);
272 va_end(args);
275 #else
276 ic_private void debug_msg(const char* fmt, ...) {
277 static int debug_init;
278 static const char* debug_fname = "isocline.debug.txt";
279 // initialize?
280 if (debug_init == 0) {
281 debug_init = -1;
282 const char* rdebug = getenv("ISOCLINE_DEBUG");
283 if (rdebug != NULL && strcmp(rdebug,"1") == 0) {
284 FILE* fdbg = fopen(debug_fname, "w");
285 if (fdbg != NULL) {
286 debug_init = 1;
287 fclose(fdbg);
291 if (debug_init <= 0) { return; }
293 // write debug messages
294 FILE* fdbg = fopen(debug_fname, "a");
295 if (fdbg == NULL) { return; }
296 va_list args;
297 va_start(args, fmt);
298 vfprintf(fdbg, fmt, args);
299 fclose(fdbg);
300 va_end(args);
302 #endif
305 //-------------------------------------------------------------
306 // Allocation
307 //-------------------------------------------------------------
309 ic_private void* mem_malloc(alloc_t* mem, ssize_t sz) {
310 return mem->malloc(to_size_t(sz));
313 ic_private void* mem_zalloc(alloc_t* mem, ssize_t sz) {
314 void* p = mem_malloc(mem, sz);
315 if (p != NULL) { memset(p, 0, to_size_t(sz)); }
316 return p;
319 ic_private void* mem_realloc(alloc_t* mem, void* p, ssize_t newsz) {
320 return mem->realloc(p, to_size_t(newsz));
323 ic_private void mem_free(alloc_t* mem, const void* p) {
324 mem->free((void*)p);
327 ic_private char* mem_strdup(alloc_t* mem, const char* s) {
328 if (s == NULL) { return NULL; }
329 ssize_t n = ic_strlen(s);
330 char* p = mem_malloc_tp_n(mem, char, n+1);
331 if (p == NULL) { return NULL; }
332 ic_memcpy(p, s, n+1);
333 return p;
336 ic_private char* mem_strndup(alloc_t* mem, const char* s, ssize_t n) {
337 if (s == NULL || n < 0) { return NULL; }
338 char* p = mem_malloc_tp_n(mem, char, n+1);
339 if (p == NULL) { return NULL; }
340 ssize_t i;
341 for (i = 0; i < n && s[i] != 0; i++) {
342 p[i] = s[i];
344 assert(i <= n);
345 p[i] = 0;
346 return p;