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 -----------------------------------------------------------------------------*/
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
) {
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
));
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; }
57 assert(dest
[slen
] == 0);
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) {
70 strncpy(dest
,src
,to_size_t(n
));
76 //-------------------------------------------------------------
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; }
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
) {
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; }
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; }
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
); }
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 //-------------------------------------------------------------
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
);
183 ic_private
void unicode_to_qutf8(unicode_t u
, uint8_t buf
[5]) {
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])) {
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
) {
217 if (len
<= 0 || s
== NULL
) {
222 if (c0
<= 0x7F && len
>= 1) {
223 if (count
!= NULL
) { *count
= 1; }
226 else if (c0
<= 0xC1) { // invalid continuation byte or invalid 0xC0, 0xC1
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
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
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));
255 if (count
!= NULL
) { *count
= 1; }
256 return unicode_from_raw(s
[0]);
260 //-------------------------------------------------------------
262 //-------------------------------------------------------------
264 #if defined(IC_NO_DEBUG_MSG)
266 #elif !defined(IC_DEBUG_TO_FILE)
267 ic_private
void debug_msg(const char* fmt
, ...) {
268 if (getenv("ISOCLINE_DEBUG")) {
271 vfprintf(stderr
, fmt
, args
);
276 ic_private
void debug_msg(const char* fmt
, ...) {
277 static int debug_init
;
278 static const char* debug_fname
= "isocline.debug.txt";
280 if (debug_init
== 0) {
282 const char* rdebug
= getenv("ISOCLINE_DEBUG");
283 if (rdebug
!= NULL
&& strcmp(rdebug
,"1") == 0) {
284 FILE* fdbg
= fopen(debug_fname
, "w");
291 if (debug_init
<= 0) { return; }
293 // write debug messages
294 FILE* fdbg
= fopen(debug_fname
, "a");
295 if (fdbg
== NULL
) { return; }
298 vfprintf(fdbg
, fmt
, args
);
305 //-------------------------------------------------------------
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
)); }
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
) {
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);
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
; }
341 for (i
= 0; i
< n
&& s
[i
] != 0; i
++) {