2016-07-07 07:04:24 +00:00
|
|
|
#include "util.h"
|
2018-10-29 19:01:20 +00:00
|
|
|
#include "platform.h"
|
2016-07-07 07:04:24 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
2018-09-26 17:39:17 +00:00
|
|
|
_Thread_local lovrErrorHandler lovrErrorCallback = NULL;
|
|
|
|
_Thread_local void* lovrErrorUserdata = NULL;
|
|
|
|
|
|
|
|
void lovrSetErrorCallback(lovrErrorHandler callback, void* userdata) {
|
|
|
|
lovrErrorCallback = callback;
|
|
|
|
lovrErrorUserdata = userdata;
|
|
|
|
}
|
2017-08-10 07:08:29 +00:00
|
|
|
|
|
|
|
void lovrThrow(const char* format, ...) {
|
2018-09-26 17:39:17 +00:00
|
|
|
if (lovrErrorCallback) {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
|
|
|
lovrErrorCallback(lovrErrorUserdata, format, args);
|
|
|
|
va_end(args);
|
|
|
|
} else {
|
|
|
|
va_list args;
|
|
|
|
va_start(args, format);
|
2018-10-29 19:01:20 +00:00
|
|
|
lovrWarn("Error: ");
|
|
|
|
lovrWarnv(format, args);
|
|
|
|
lovrWarn("\n");
|
2018-09-26 17:39:17 +00:00
|
|
|
va_end(args);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2017-08-10 07:08:29 +00:00
|
|
|
}
|
|
|
|
|
2018-07-25 02:14:29 +00:00
|
|
|
void* _lovrAlloc(const char* type, size_t size, void (*destructor)(void*)) {
|
2018-03-21 19:56:16 +00:00
|
|
|
void* object = calloc(1, size);
|
2016-11-19 08:37:43 +00:00
|
|
|
if (!object) return NULL;
|
2018-12-10 23:18:42 +00:00
|
|
|
*((Ref*) object) = (Ref) { .free = destructor, .type = type, .count = 1 };
|
2016-11-19 08:37:43 +00:00
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
2018-02-26 08:59:03 +00:00
|
|
|
void lovrRetain(void* object) {
|
|
|
|
if (object) ((Ref*) object)->count++;
|
2016-11-19 08:37:43 +00:00
|
|
|
}
|
|
|
|
|
2018-02-26 08:59:03 +00:00
|
|
|
void lovrRelease(void* object) {
|
|
|
|
Ref* ref = object;
|
|
|
|
if (ref && --ref->count == 0) ref->free(object);
|
2016-11-19 08:37:43 +00:00
|
|
|
}
|
2017-02-06 09:54:11 +00:00
|
|
|
|
|
|
|
// https://github.com/starwing/luautf8
|
|
|
|
size_t utf8_decode(const char *s, const char *e, unsigned *pch) {
|
|
|
|
unsigned ch;
|
|
|
|
|
|
|
|
if (s >= e) {
|
|
|
|
*pch = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch = (unsigned char)s[0];
|
|
|
|
if (ch < 0xC0) goto fallback;
|
|
|
|
if (ch < 0xE0) {
|
|
|
|
if (s+1 >= e || (s[1] & 0xC0) != 0x80)
|
|
|
|
goto fallback;
|
|
|
|
*pch = ((ch & 0x1F) << 6) |
|
|
|
|
(s[1] & 0x3F);
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
if (ch < 0xF0) {
|
|
|
|
if (s+2 >= e || (s[1] & 0xC0) != 0x80
|
|
|
|
|| (s[2] & 0xC0) != 0x80)
|
|
|
|
goto fallback;
|
|
|
|
*pch = ((ch & 0x0F) << 12) |
|
|
|
|
((s[1] & 0x3F) << 6) |
|
|
|
|
(s[2] & 0x3F);
|
|
|
|
return 3;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
int count = 0; /* to count number of continuation bytes */
|
|
|
|
unsigned res = 0;
|
|
|
|
while ((ch & 0x40) != 0) { /* still have continuation bytes? */
|
|
|
|
int cc = (unsigned char)s[++count];
|
|
|
|
if ((cc & 0xC0) != 0x80) /* not a continuation byte? */
|
|
|
|
goto fallback; /* invalid byte sequence, fallback */
|
|
|
|
res = (res << 6) | (cc & 0x3F); /* add lower 6 bits from cont. byte */
|
|
|
|
ch <<= 1; /* to test next bit */
|
|
|
|
}
|
|
|
|
if (count > 5)
|
|
|
|
goto fallback; /* invalid byte sequence */
|
|
|
|
res |= ((ch & 0x7F) << (count * 5)); /* add first byte */
|
|
|
|
*pch = res;
|
|
|
|
return count+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
fallback:
|
|
|
|
*pch = ch;
|
|
|
|
return 1;
|
|
|
|
}
|
2018-03-21 21:48:46 +00:00
|
|
|
|
|
|
|
uint32_t nextPo2(uint32_t x) {
|
|
|
|
x--;
|
|
|
|
x |= x >> 1;
|
|
|
|
x |= x >> 2;
|
|
|
|
x |= x >> 4;
|
|
|
|
x |= x >> 8;
|
|
|
|
x |= x >> 16;
|
|
|
|
x++;
|
|
|
|
return x;
|
|
|
|
}
|