nota leaks fixed
This commit is contained in:
parent
46b86a8e92
commit
262cd50e1a
|
@ -91,14 +91,14 @@
|
||||||
*/
|
*/
|
||||||
//#define DUMP_BYTECODE (1)
|
//#define DUMP_BYTECODE (1)
|
||||||
/* dump the occurence of the automatic GC */
|
/* dump the occurence of the automatic GC */
|
||||||
//#define DUMP_GC
|
#define DUMP_GC
|
||||||
/* dump objects freed by the garbage collector */
|
/* dump objects freed by the garbage collector */
|
||||||
//#define DUMP_GC_FREE
|
//#define DUMP_GC_FREE
|
||||||
/* dump objects leaking when freeing the runtime */
|
/* dump objects leaking when freeing the runtime */
|
||||||
//#define DUMP_LEAKS 1
|
#define DUMP_LEAKS 1
|
||||||
/* dump memory usage before running the garbage collector */
|
/* dump memory usage before running the garbage collector */
|
||||||
//#define DUMP_MEM
|
#define DUMP_MEM
|
||||||
//#define DUMP_OBJECTS /* dump objects in JS_FreeContext */
|
#define DUMP_OBJECTS /* dump objects in JS_FreeContext */
|
||||||
//#define DUMP_ATOMS /* dump atoms in JS_FreeContext */
|
//#define DUMP_ATOMS /* dump atoms in JS_FreeContext */
|
||||||
//#define DUMP_SHAPES /* dump shapes in JS_FreeContext */
|
//#define DUMP_SHAPES /* dump shapes in JS_FreeContext */
|
||||||
//#define DUMP_MODULE_RESOLVE
|
//#define DUMP_MODULE_RESOLVE
|
||||||
|
|
|
@ -562,7 +562,7 @@ var editor = {
|
||||||
} else {
|
} else {
|
||||||
var path = sub.replaceAll('.', '/') + ".json";
|
var path = sub.replaceAll('.', '/') + ".json";
|
||||||
var saveobj = obj.json_obj();
|
var saveobj = obj.json_obj();
|
||||||
IO.slurpwrite(JSON.stringify(saveobj,null,1), path);
|
IO.slurpwrite(path, JSON.stringify(saveobj,null,1));
|
||||||
|
|
||||||
if (obj === editor.edit_level) {
|
if (obj === editor.edit_level) {
|
||||||
if (obj === editor.desktop) {
|
if (obj === editor.desktop) {
|
||||||
|
@ -841,7 +841,7 @@ editor.inputs['C-s'] = function() {
|
||||||
if (savejs.objects) saveobj.__proto__.objects = savejs.objects;
|
if (savejs.objects) saveobj.__proto__.objects = savejs.objects;
|
||||||
var path = prototypes.ur_stem(saveobj.ur.toString()) + ".json";
|
var path = prototypes.ur_stem(saveobj.ur.toString()) + ".json";
|
||||||
|
|
||||||
IO.slurpwrite(JSON.stringify(saveobj.__proto__,null,1), path);
|
IO.slurpwrite(path, JSON.stringify(saveobj.__proto__,null,1));
|
||||||
Log.warn(`Wrote to file ${path}`);
|
Log.warn(`Wrote to file ${path}`);
|
||||||
|
|
||||||
Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); });
|
Object.values(saveobj.objects).forEach(function(x) { x.check_dirty(); });
|
||||||
|
|
|
@ -760,7 +760,6 @@ gameobject.doc = {
|
||||||
var prototypes = {};
|
var prototypes = {};
|
||||||
prototypes.ur_ext = ".jso";
|
prototypes.ur_ext = ".jso";
|
||||||
prototypes.ur = {};
|
prototypes.ur = {};
|
||||||
prototypes.save_gameobjects = function() { slurpwrite(JSON.stringify(gameobjects,null,2), "proto.json"); };
|
|
||||||
|
|
||||||
/* Makes a new ur-type from disk. If the ur doesn't exist, it searches on the disk to create it. */
|
/* Makes a new ur-type from disk. If the ur doesn't exist, it searches on the disk to create it. */
|
||||||
prototypes.from_file = function(file)
|
prototypes.from_file = function(file)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
var Sound = {
|
var Sound = {
|
||||||
bus: {},
|
bus: {},
|
||||||
samplerate() { return cmd(198); },
|
samplerate() { return cmd(198); },
|
||||||
|
@ -108,9 +107,10 @@ Object.mixin(cmd(180).__proto__, {
|
||||||
set volume(x) { this.gain = x; },
|
set volume(x) { this.gain = x; },
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.mixin(DSP.source().__proto__, {
|
/*Object.mixin(DSP.source().__proto__, {
|
||||||
frames() { return cmd(197,this); },
|
frames() { return cmd(197,this); },
|
||||||
length() { return this.frames()/Sound.samplerate(); },
|
length() { return this.frames()/Sound.samplerate(); },
|
||||||
time() { return this.frame/Sound.samplerate(); },
|
time() { return this.frame/Sound.samplerate(); },
|
||||||
pct() { return this.time()/this.length(); },
|
pct() { return this.time()/this.length(); },
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
|
|
@ -6,6 +6,12 @@ function compile_env(str, env, file)
|
||||||
|
|
||||||
function fcompile_env(file, env) { return compile_env(IO.slurp(file), env, file); }
|
function fcompile_env(file, env) { return compile_env(IO.slurp(file), env, file); }
|
||||||
|
|
||||||
|
function buf2hex(buffer) { // buffer is an ArrayBuffer
|
||||||
|
return [...new Uint8Array(buffer)]
|
||||||
|
.map(x => x.toString(16).padStart(2, '0'))
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
var OS = {};
|
var OS = {};
|
||||||
OS.cwd = function() { return cmd(144); }
|
OS.cwd = function() { return cmd(144); }
|
||||||
OS.exec = function(s) { cmd(143, s); }
|
OS.exec = function(s) { cmd(143, s); }
|
||||||
|
@ -140,7 +146,15 @@ var IO = {
|
||||||
else
|
else
|
||||||
throw new Error(`File ${file} does not exist; can't slurp`);
|
throw new Error(`File ${file} does not exist; can't slurp`);
|
||||||
},
|
},
|
||||||
slurpwrite(str, file) { return cmd(39, str, file); },
|
slurpbytes(file) {
|
||||||
|
return cmd(81, file);
|
||||||
|
},
|
||||||
|
slurpwrite(file, data) {
|
||||||
|
if (data.byteLength)
|
||||||
|
cmd(60, data, file);
|
||||||
|
else
|
||||||
|
return cmd(39, data, file);
|
||||||
|
},
|
||||||
extensions(ext) {
|
extensions(ext) {
|
||||||
var paths = IO.ls();
|
var paths = IO.ls();
|
||||||
paths = paths.filter(function(str) { return str.ext() === ext; });
|
paths = paths.filter(function(str) { return str.ext() === ext; });
|
||||||
|
@ -312,7 +326,6 @@ Cmdline.register_cmd("cjson", function(json) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.say(j);
|
Log.say(j);
|
||||||
// IO.slurpwrite(JSON.stringify(j,undefined,2), f);
|
|
||||||
|
|
||||||
STD.exit(0);
|
STD.exit(0);
|
||||||
}, "Clean up a jso file.");
|
}, "Clean up a jso file.");
|
||||||
|
|
|
@ -19,7 +19,6 @@ HMM_Vec2 mouse_delta = {0, 0};
|
||||||
|
|
||||||
struct joystick {
|
struct joystick {
|
||||||
int id;
|
int id;
|
||||||
//GLFWgamepadstate state;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int *downkeys = NULL;
|
static int *downkeys = NULL;
|
||||||
|
|
|
@ -162,8 +162,8 @@ JSValue js_getpropidx(JSValue v, uint32_t i)
|
||||||
|
|
||||||
static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; }
|
static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; }
|
||||||
|
|
||||||
uint64_t js2uint64(JSValue v) {
|
int64_t js2int64(JSValue v) {
|
||||||
uint64_t i;
|
int64_t i;
|
||||||
JS_ToInt64(js, &i, v);
|
JS_ToInt64(js, &i, v);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
@ -247,6 +247,8 @@ char *js_nota_decode(JSValue *tmp, char *nota)
|
||||||
case NOTA_TEXT:
|
case NOTA_TEXT:
|
||||||
nota = nota_read_text(&str, nota);
|
nota = nota_read_text(&str, nota);
|
||||||
*tmp = str2js(str);
|
*tmp = str2js(str);
|
||||||
|
/* TODO: Avoid malloc and free here */
|
||||||
|
free(str);
|
||||||
break;
|
break;
|
||||||
case NOTA_ARR:
|
case NOTA_ARR:
|
||||||
nota = nota_read_array(&n, nota);
|
nota = nota_read_array(&n, nota);
|
||||||
|
@ -258,14 +260,12 @@ char *js_nota_decode(JSValue *tmp, char *nota)
|
||||||
break;
|
break;
|
||||||
case NOTA_REC:
|
case NOTA_REC:
|
||||||
nota = nota_read_record(&n, nota);
|
nota = nota_read_record(&n, nota);
|
||||||
printf("nota object with %d elements\n", n);
|
|
||||||
*tmp = JS_NewObject(js);
|
*tmp = JS_NewObject(js);
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < n; i++) {
|
||||||
|
|
||||||
nota = nota_read_text(&str, nota);
|
nota = nota_read_text(&str, nota);
|
||||||
printf("looking at property %d named %s\n", i, str);
|
|
||||||
nota = js_nota_decode(&ret2, nota);
|
nota = js_nota_decode(&ret2, nota);
|
||||||
JS_SetPropertyStr(js, *tmp, str, ret2);
|
JS_SetPropertyStr(js, *tmp, str, ret2);
|
||||||
|
free(str);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NOTA_INT:
|
case NOTA_INT:
|
||||||
|
@ -273,8 +273,10 @@ char *js_nota_decode(JSValue *tmp, char *nota)
|
||||||
*tmp = int2js(n);
|
*tmp = int2js(n);
|
||||||
break;
|
break;
|
||||||
case NOTA_SYM:
|
case NOTA_SYM:
|
||||||
nota = nota_read_bool(&b, nota);
|
nota = nota_read_sym(&b, nota);
|
||||||
*tmp = bool2js(b);
|
if (b == NOTA_NULL) *tmp = JS_UNDEFINED;
|
||||||
|
else
|
||||||
|
*tmp = bool2js(b);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
case NOTA_FLOAT:
|
case NOTA_FLOAT:
|
||||||
|
@ -297,42 +299,44 @@ char *js_nota_encode(JSValue v, char *nota)
|
||||||
|
|
||||||
switch(tag) {
|
switch(tag) {
|
||||||
case JS_TAG_FLOAT64:
|
case JS_TAG_FLOAT64:
|
||||||
// printf("encode float\n");
|
|
||||||
return nota_write_float(JS_VALUE_GET_FLOAT64(v), nota);
|
return nota_write_float(JS_VALUE_GET_FLOAT64(v), nota);
|
||||||
case JS_TAG_INT:
|
case JS_TAG_INT:
|
||||||
// printf("encode int\n");
|
|
||||||
return nota_write_int(JS_VALUE_GET_INT(v), nota);
|
return nota_write_int(JS_VALUE_GET_INT(v), nota);
|
||||||
case JS_TAG_STRING:
|
case JS_TAG_STRING:
|
||||||
// printf("encode string\n");
|
|
||||||
str = js2str(v);
|
str = js2str(v);
|
||||||
nota = nota_write_text(str, nota);
|
nota = nota_write_text(str, nota);
|
||||||
JS_FreeCString(js, str);
|
JS_FreeCString(js, str);
|
||||||
return nota;
|
return nota;
|
||||||
case JS_TAG_BOOL:
|
case JS_TAG_BOOL:
|
||||||
// printf("encode bool\n");
|
return nota_write_sym(JS_VALUE_GET_BOOL(v), nota);
|
||||||
return nota_write_bool(JS_VALUE_GET_BOOL(v), nota);
|
case JS_TAG_UNDEFINED:
|
||||||
|
return nota_write_sym(NOTA_NULL, nota);
|
||||||
|
case JS_TAG_NULL:
|
||||||
|
return nota_write_sym(NOTA_NULL, nota);
|
||||||
case JS_TAG_OBJECT:
|
case JS_TAG_OBJECT:
|
||||||
if (JS_IsArray(js, v)) {
|
if (JS_IsArray(js, v)) {
|
||||||
// printf("encode array\n");
|
|
||||||
int n = js_arrlen(v);
|
int n = js_arrlen(v);
|
||||||
nota = nota_write_array(n, nota);
|
nota = nota_write_array(n, nota);
|
||||||
for (int i = 0; i < js_arrlen(v); i++)
|
for (int i = 0; i < n; i++)
|
||||||
nota = js_nota_encode(js_arridx(v, i), nota);
|
nota = js_nota_encode(js_arridx(v, i), nota);
|
||||||
return nota;
|
return nota;
|
||||||
}
|
}
|
||||||
// printf("encode object\n");
|
|
||||||
|
|
||||||
n = JS_GetOwnPropertyNames(js, &ptab, &plen, v, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
|
n = JS_GetOwnPropertyNames(js, &ptab, &plen, v, JS_GPN_ENUM_ONLY | JS_GPN_STRING_MASK);
|
||||||
nota = nota_write_record(plen, nota);
|
nota = nota_write_record(plen, nota);
|
||||||
|
|
||||||
for (int i = 0; i < plen; i++) {
|
for (int i = 0; i < plen; i++) {
|
||||||
val = JS_GetProperty(js,v,ptab[i].atom);
|
val = JS_GetProperty(js,v,ptab[i].atom);
|
||||||
if (JS_IsUndefined(val) || JS_IsNull(val)) continue;
|
|
||||||
/* todo: slower than atomtocstring */
|
|
||||||
str = JS_AtomToCString(js, ptab[i].atom);
|
str = JS_AtomToCString(js, ptab[i].atom);
|
||||||
// printf("encoding object entry %s\n", str);
|
JS_FreeAtom(js, ptab[i].atom);
|
||||||
|
|
||||||
nota = nota_write_text(str, nota);
|
nota = nota_write_text(str, nota);
|
||||||
nota = js_nota_encode(JS_GetProperty(js, v, ptab[i].atom), nota);
|
JS_FreeCString(js, str);
|
||||||
|
|
||||||
|
nota = js_nota_encode(val, nota);
|
||||||
|
JS_FreeValue(js,val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
js_free(js, ptab);
|
||||||
return nota;
|
return nota;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -666,6 +670,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
int *intids = NULL;
|
int *intids = NULL;
|
||||||
gameobject *go = NULL;
|
gameobject *go = NULL;
|
||||||
JSValue ret = JS_UNDEFINED;
|
JSValue ret = JS_UNDEFINED;
|
||||||
|
size_t plen = 0;
|
||||||
|
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -807,9 +812,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 39:
|
case 39:
|
||||||
str = JS_ToCString(js, argv[1]);
|
str = JS_ToCStringLen(js, &plen, argv[1]);
|
||||||
str2 = JS_ToCString(js, argv[2]);
|
str2 = JS_ToCString(js, argv[2]);
|
||||||
ret = JS_NewInt64(js, slurp_write(str, str2));
|
ret = JS_NewInt64(js, slurp_write(str, str2, plen));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 40:
|
case 40:
|
||||||
|
@ -883,6 +888,10 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 60:
|
case 60:
|
||||||
|
str = JS_GetArrayBuffer(js, &plen, argv[1]);
|
||||||
|
str2 = JS_ToCString(js, argv[2]);
|
||||||
|
ret = JS_NewInt64(js, slurp_write(str, str2, plen));
|
||||||
|
str = NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 61:
|
case 61:
|
||||||
|
@ -961,6 +970,12 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
arrfree(ids);
|
arrfree(ids);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 81:
|
||||||
|
str = JS_ToCString(js, argv[1]);
|
||||||
|
d1 = slurp_file(str, &plen);
|
||||||
|
ret = JS_NewArrayBufferCopy(js, d1, plen);
|
||||||
|
break;
|
||||||
|
|
||||||
case 82:
|
case 82:
|
||||||
gameobject_draw_debug(js2gameobject(argv[1]));
|
gameobject_draw_debug(js2gameobject(argv[1]));
|
||||||
break;
|
break;
|
||||||
|
@ -1101,15 +1116,15 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 128:
|
case 128:
|
||||||
ret = JS_NewFloat64(js, stm_ns(js2uint64(argv[1])));
|
ret = JS_NewFloat64(js, stm_ns(js2int64(argv[1])));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 129:
|
case 129:
|
||||||
ret = JS_NewFloat64(js, stm_us(js2uint64(argv[1])));
|
ret = JS_NewFloat64(js, stm_us(js2int64(argv[1])));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 130:
|
case 130:
|
||||||
ret = JS_NewFloat64(js, stm_ms(js2uint64(argv[1])));
|
ret = JS_NewFloat64(js, stm_ms(js2int64(argv[1])));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 131:
|
case 131:
|
||||||
|
@ -2041,7 +2056,7 @@ JSValue nota_encode(JSContext *js, JSValueConst this, int argc, JSValueConst *ar
|
||||||
if (argc < 1) return JS_UNDEFINED;
|
if (argc < 1) return JS_UNDEFINED;
|
||||||
|
|
||||||
JSValue obj = argv[0];
|
JSValue obj = argv[0];
|
||||||
char nota[100000];
|
char nota[1024*1024]; // 1MB
|
||||||
char *e = js_nota_encode(obj, nota);
|
char *e = js_nota_encode(obj, nota);
|
||||||
|
|
||||||
return JS_NewArrayBufferCopy(js, nota, e-nota);
|
return JS_NewArrayBufferCopy(js, nota, e-nota);
|
||||||
|
@ -2107,6 +2122,7 @@ void ffi_load() {
|
||||||
sound_proto = JS_NewObject(js);
|
sound_proto = JS_NewObject(js);
|
||||||
JS_SetPropertyFunctionList(js, sound_proto, js_sound_funcs, countof(js_sound_funcs));
|
JS_SetPropertyFunctionList(js, sound_proto, js_sound_funcs, countof(js_sound_funcs));
|
||||||
JS_SetPrototype(js, sound_proto, dsp_node_proto);
|
JS_SetPrototype(js, sound_proto, dsp_node_proto);
|
||||||
|
JS_FreeValue(js, sound_proto);
|
||||||
|
|
||||||
QJSCLASSPREP_FUNCS(emitter);
|
QJSCLASSPREP_FUNCS(emitter);
|
||||||
QJSCLASSPREP_FUNCS(warp_gravity);
|
QJSCLASSPREP_FUNCS(warp_gravity);
|
||||||
|
|
|
@ -1,2 +1,101 @@
|
||||||
#include "kim.h"
|
#include "kim.h"
|
||||||
|
|
||||||
|
#define KIM_CONT 0x80
|
||||||
|
#define KIM_DATA 0x7f
|
||||||
|
#define CONTINUE(CHAR) (CHAR>>7)
|
||||||
|
|
||||||
|
int utf8_bytes(char *s)
|
||||||
|
{
|
||||||
|
int bytes = __builtin_clz(~(*s));
|
||||||
|
if (!bytes) return 1;
|
||||||
|
return bytes-24;
|
||||||
|
}
|
||||||
|
|
||||||
|
int utf8_count(char *s)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
char *p = s;
|
||||||
|
|
||||||
|
while(*s) {
|
||||||
|
count++;
|
||||||
|
s += utf8_bytes(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode and advance s, returning the character cde */
|
||||||
|
int decode_utf8(char **s) {
|
||||||
|
int k = **s ? __builtin_clz(~(**s << 24)) : 0; // Count # of leading 1 bits.
|
||||||
|
int mask = (1 << (8 - k)) - 1; // All 1's with k leading 0's.
|
||||||
|
int value = **s & mask;
|
||||||
|
for (++(*s), --k; k > 0 && **s; --k, ++(*s)) { // Note that k = #total bytes, or 0.
|
||||||
|
value <<= 6;
|
||||||
|
value += (**s & 0x3F);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write and advance s with code in utf-8 */
|
||||||
|
void encode_utf8(char **s, int code) {
|
||||||
|
char val[4];
|
||||||
|
int lead_byte_max = 0x7F;
|
||||||
|
int val_index = 0;
|
||||||
|
while (code > lead_byte_max) {
|
||||||
|
val[val_index++] = (code & 0x3F) | 0x80;
|
||||||
|
code >>= 6;
|
||||||
|
lead_byte_max >>= (val_index == 1 ? 2 : 1);
|
||||||
|
}
|
||||||
|
val[val_index++] = (code & lead_byte_max) | (~lead_byte_max << 1);
|
||||||
|
while (val_index--) {
|
||||||
|
**s = val[val_index];
|
||||||
|
(*s)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write and advance s with code in kim */
|
||||||
|
void encode_kim(char **s, int code)
|
||||||
|
{
|
||||||
|
if (code < KIM_CONT) {
|
||||||
|
**s = 0 | (KIM_DATA & code);
|
||||||
|
(*s)++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bits = ((32 - __builtin_clz(code) + 6) / 7) * 7;
|
||||||
|
|
||||||
|
while (bits > 7) {
|
||||||
|
bits -= 7;
|
||||||
|
**s = KIM_CONT | KIM_DATA & (code >> bits);
|
||||||
|
(*s)++;
|
||||||
|
}
|
||||||
|
**s = KIM_DATA & code;
|
||||||
|
(*s)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decode and advance s, returning the character code */
|
||||||
|
int decode_kim(char **s)
|
||||||
|
{
|
||||||
|
int rune = **s & KIM_DATA;
|
||||||
|
while (CONTINUE(**s)) {
|
||||||
|
rune <<= 7;
|
||||||
|
(*s)++;
|
||||||
|
rune |= **s & KIM_DATA;
|
||||||
|
}
|
||||||
|
(*s)++;
|
||||||
|
return rune;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write a null-terminated utf8 stream into a kim string */
|
||||||
|
void utf8_to_kim(char **utf, char **kim)
|
||||||
|
{
|
||||||
|
while (**utf)
|
||||||
|
encode_kim(kim, decode_utf8(utf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write number of runes from a kim stream int a utf8 stream */
|
||||||
|
void kim_to_utf8(char **kim, char **utf, int runes)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < runes; i++)
|
||||||
|
encode_utf8(utf, decode_kim(kim));
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
#ifndef KIM_H
|
#ifndef KIM_H
|
||||||
#define KIM_H
|
#define KIM_H
|
||||||
|
|
||||||
void write_kim_char(char c, char *into);
|
int utf8_bytes(char *s);
|
||||||
|
int utf8_count(char *s);
|
||||||
|
int decode_utf8(char **s);
|
||||||
|
void encode_utf8(char **s, int code);
|
||||||
|
void encode_kim(char **s, int code);
|
||||||
|
int decode_kim(char **s);
|
||||||
|
void utf8_to_kim(char **utf, char **kim);
|
||||||
|
void kim_to_utf8(char **kim, char **utf, int runes);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
#include "limits.h"
|
#include "limits.h"
|
||||||
|
#include "kim.h"
|
||||||
|
|
||||||
#define NOTA_CONT 0x80
|
#define NOTA_CONT 0x80
|
||||||
#define NOTA_DATA 0x7f
|
#define NOTA_DATA 0x7f
|
||||||
|
@ -15,13 +16,11 @@
|
||||||
#define NOTA_HEAD_DATA 0x0f
|
#define NOTA_HEAD_DATA 0x0f
|
||||||
#define CONTINUE(CHAR) (CHAR>>7)
|
#define CONTINUE(CHAR) (CHAR>>7)
|
||||||
|
|
||||||
#define NOTA_FALSE 0x00
|
|
||||||
#define NOTA_TRUE 0x01
|
|
||||||
#define NOTA_PRIVATE 0x08
|
|
||||||
#define NOTA_SYSTEM 0x09
|
|
||||||
|
|
||||||
#define UTF8_DATA 0x3f
|
#define UTF8_DATA 0x3f
|
||||||
|
|
||||||
|
/* define this to use native string instead of kim. Bytes are encoded instead of runes */
|
||||||
|
#define NOTA_UTF8
|
||||||
|
|
||||||
int nota_type(char *nota) { return *nota & NOTA_TYPE; }
|
int nota_type(char *nota) { return *nota & NOTA_TYPE; }
|
||||||
|
|
||||||
char *nota_skip(char *nota)
|
char *nota_skip(char *nota)
|
||||||
|
@ -240,136 +239,52 @@ char *nota_write_record(unsigned long long n, char *nota)
|
||||||
return nota_continue_num(n, nota, 4);
|
return nota_continue_num(n, nota, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* kim is 7, 14, then 21 */
|
char *nota_write_sym(int sym, char *nota)
|
||||||
|
|
||||||
int utf8_bytes(char *s)
|
|
||||||
{
|
{
|
||||||
int bytes = __builtin_clz(~(*s));
|
*nota = NOTA_SYM | sym;
|
||||||
if (!bytes) return 1;
|
return nota+1;
|
||||||
return bytes-24;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int utf8_count(char *s)
|
char *nota_read_sym(int *sym, char *nota)
|
||||||
{
|
{
|
||||||
int count = 0;
|
if (*sym) *sym = (*nota) & 0x0f;
|
||||||
char *p = s;
|
return nota+1;
|
||||||
|
|
||||||
while(*s) {
|
|
||||||
count++;
|
|
||||||
s += utf8_bytes(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
int decode_utf8(char **s) {
|
|
||||||
int k = **s ? __builtin_clz(~(**s << 24)) : 0; // Count # of leading 1 bits.
|
|
||||||
int mask = (1 << (8 - k)) - 1; // All 1's with k leading 0's.
|
|
||||||
int value = **s & mask;
|
|
||||||
for (++(*s), --k; k > 0 && **s; --k, ++(*s)) { // Note that k = #total bytes, or 0.
|
|
||||||
value <<= 6;
|
|
||||||
value += (**s & 0x3F);
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode_utf8(char **s, char *end, int code) {
|
|
||||||
if (code < 255) {
|
|
||||||
**s = code;
|
|
||||||
(*s)++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char val[4];
|
|
||||||
int lead_byte_max = 0x7F;
|
|
||||||
int val_index = 0;
|
|
||||||
while (code > lead_byte_max) {
|
|
||||||
val[val_index++] = (code & 0x3F) | 0x80;
|
|
||||||
code >>= 6;
|
|
||||||
lead_byte_max >>= (val_index == 1 ? 2 : 1);
|
|
||||||
}
|
|
||||||
val[val_index++] = (code & lead_byte_max) | (~lead_byte_max << 1);
|
|
||||||
while (val_index-- && *s < end) {
|
|
||||||
**s = val[val_index];
|
|
||||||
(*s)++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void encode_kim(char **s, char *end, int code)
|
|
||||||
{
|
|
||||||
if (code < 255) {
|
|
||||||
**s = 0 | (NOTA_DATA & code);
|
|
||||||
(*s)++;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int bits = ((32 - __builtin_clz(code) + 6) / 7) * 7;
|
|
||||||
|
|
||||||
while (bits > 7) {
|
|
||||||
bits -= 7;
|
|
||||||
**s = NOTA_CONT | NOTA_DATA & (code >> bits);
|
|
||||||
(*s)++;
|
|
||||||
}
|
|
||||||
**s = NOTA_DATA & code;
|
|
||||||
(*s)++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int decode_kim(char **s)
|
|
||||||
{
|
|
||||||
int rune = **s & NOTA_DATA;
|
|
||||||
while (CONTINUE(**s)) {
|
|
||||||
rune <<= 7;
|
|
||||||
(*s)++;
|
|
||||||
rune |= **s & NOTA_DATA;
|
|
||||||
}
|
|
||||||
(*s)++;
|
|
||||||
return rune;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *utf8_to_kim(char *utf, char *kim)
|
|
||||||
{
|
|
||||||
while (*utf)
|
|
||||||
encode_kim(&kim, NULL, decode_utf8(&utf));
|
|
||||||
|
|
||||||
return kim;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kim_to_utf8(char *kim, char *utf, int runes)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < runes; i++)
|
|
||||||
encode_utf8(&utf, utf+4, decode_kim(&kim));
|
|
||||||
|
|
||||||
*utf = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_read_text(char **text, char *nota)
|
char *nota_read_text(char **text, char *nota)
|
||||||
{
|
{
|
||||||
long long chars;
|
long long chars;
|
||||||
nota = nota_read_num(&chars, nota);
|
nota = nota_read_num(&chars, nota);
|
||||||
|
|
||||||
|
#ifdef NOTA_UTF8
|
||||||
|
*text = calloc(chars+1,1);
|
||||||
|
memcpy(*text, nota, chars);
|
||||||
|
nota += chars;
|
||||||
|
#else
|
||||||
char utf[chars*4];
|
char utf[chars*4];
|
||||||
kim_to_utf8(nota, utf, chars);
|
char *pp = utf;
|
||||||
|
kim_to_utf8(¬a, &pp, chars);
|
||||||
|
*pp = 0;
|
||||||
*text = strdup(utf);
|
*text = strdup(utf);
|
||||||
|
#endif
|
||||||
|
|
||||||
return nota;
|
return nota;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *nota_write_bool(int b, char *nota)
|
|
||||||
{
|
|
||||||
*nota = NOTA_SYM | (b ? NOTA_TRUE : NOTA_FALSE);
|
|
||||||
return nota+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *nota_read_bool(int *b, char *nota)
|
|
||||||
{
|
|
||||||
if (b) *b = (*nota) & 0x0f;
|
|
||||||
return nota+1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *nota_write_text(char *s, char *nota)
|
char *nota_write_text(char *s, char *nota)
|
||||||
{
|
{
|
||||||
char *start = nota;
|
|
||||||
nota[0] = NOTA_TEXT;
|
nota[0] = NOTA_TEXT;
|
||||||
|
|
||||||
|
#ifdef NOTA_UTF8
|
||||||
|
long long n = strlen(s);
|
||||||
|
nota = nota_continue_num(n,nota,4);
|
||||||
|
memcpy(nota, s, n);
|
||||||
|
return nota+n;
|
||||||
|
#else
|
||||||
long long n = utf8_count(s);
|
long long n = utf8_count(s);
|
||||||
nota = nota_continue_num(n,nota,4);
|
nota = nota_continue_num(n,nota,4);
|
||||||
return utf8_to_kim(s, nota);
|
utf8_to_kim(&s, ¬a);
|
||||||
|
return nota;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,12 @@
|
||||||
#define NOTA_INT 0x60
|
#define NOTA_INT 0x60
|
||||||
#define NOTA_SYM 0x70
|
#define NOTA_SYM 0x70
|
||||||
|
|
||||||
|
#define NOTA_FALSE 0x00
|
||||||
|
#define NOTA_TRUE 0x01
|
||||||
|
#define NOTA_PRIVATE 0x08
|
||||||
|
#define NOTA_SYSTEM 0x09
|
||||||
|
#define NOTA_NULL 0x02
|
||||||
|
|
||||||
typedef struct NOTA {
|
typedef struct NOTA {
|
||||||
char *head;
|
char *head;
|
||||||
} NOTA;
|
} NOTA;
|
||||||
|
@ -21,7 +27,7 @@ char *nota_read_array(long long *len, char *nota);
|
||||||
char *nota_read_record(long long *len, char *nota);
|
char *nota_read_record(long long *len, char *nota);
|
||||||
char *nota_read_float(double *d, char *nota);
|
char *nota_read_float(double *d, char *nota);
|
||||||
char *nota_read_int(long long *l, char *nota);
|
char *nota_read_int(long long *l, char *nota);
|
||||||
char *nota_read_bool(int *b, char *nota);
|
char *nota_read_sym(int *sym, char *nota);
|
||||||
|
|
||||||
void print_nota_hex(char *nota);
|
void print_nota_hex(char *nota);
|
||||||
|
|
||||||
|
@ -31,6 +37,6 @@ char *nota_write_array(unsigned long long n, char *nota);
|
||||||
char *nota_write_record(unsigned long long n, char *nota);
|
char *nota_write_record(unsigned long long n, char *nota);
|
||||||
char *nota_write_float(double n, char *nota);
|
char *nota_write_float(double n, char *nota);
|
||||||
char *nota_write_int(long long n, char *nota);
|
char *nota_write_int(long long n, char *nota);
|
||||||
char *nota_write_bool(int b, char *nota);
|
char *nota_write_sym(int sym, char *nota);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -291,11 +291,12 @@ FILE *fopen_mkdir(const char *path, const char *mode) {
|
||||||
return fopen(path,mode);
|
return fopen(path,mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int slurp_write(const char *txt, const char *filename) {
|
int slurp_write(const char *txt, const char *filename, size_t len) {
|
||||||
FILE *f = fopen_mkdir(filename, "w");
|
FILE *f = fopen_mkdir(filename, "w");
|
||||||
if (!f) return 1;
|
if (!f) return 1;
|
||||||
|
|
||||||
fputs(txt, f);
|
if (len < 0) len = strlen(txt);
|
||||||
|
fwrite(txt, len, 1, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ char *dirname(const char *path);
|
||||||
|
|
||||||
void *slurp_file(const char *filename, size_t *size);
|
void *slurp_file(const char *filename, size_t *size);
|
||||||
char *slurp_text(const char *filename, size_t *size);
|
char *slurp_text(const char *filename, size_t *size);
|
||||||
int slurp_write(const char *txt, const char *filename);
|
int slurp_write(const char *txt, const char *filename, size_t len);
|
||||||
|
|
||||||
char *seprint(char *fmt, ...);
|
char *seprint(char *fmt, ...);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue