import "io" import "heap" export { new_string, string_length, string_addchar, string_getchar, string_setchar, string_print, string_frombcplstring, string_delete } manifest { string_len = 0, // length and capacity are measured in characters string_cap = 1, string_array = 2, sizeof_emptystring = 3 } let new_string() be { let r = newvec(sizeof_emptystring); if r = nil then resultis r; r ! string_len := 0; r ! string_cap := 0; r ! string_array := nil; resultis r } let string_grow(s) be { let oldcap = s ! string_cap; let oldarraysize = (oldcap + 3) / 4; let oldarray = s ! string_array; let newcap = oldcap < 4 -> 4, oldcap * 2; let newarraysize = (newcap + 3) / 4; let newarray = newvec(newarraysize); if newarray = nil then resultis false; if oldarray <> nil then { $memory_move(newarray, oldarray, oldarraysize); freevec(oldarray); } s ! string_cap := newcap; s ! string_array := newarray; resultis true } let string_length(s) be resultis s ! string_len; let string_addchar(s, c) be { let ok; if s ! string_len >= s ! string_cap then { ok := string_grow(s); if not ok then resultis false; } byte s ! string_len of s ! string_array := c; s ! string_len +:= 1; resultis true } let string_getchar(s, i) be { if i < 0 \/ i >= s ! string_len then resultis 0; resultis byte i of s ! string_array } let string_setchar(s, i, c) be { if i < 0 then resultis false; if i > s ! string_len then resultis string_addchar(s, c); byte i of s ! string_array := c; resultis true } let string_print(s) be { let array = s ! string_array; for i = 0 to s ! string_len - 1 do outch(byte i of array) } let string_frombcplstring(s) be { let i = 0, r = new_string(); while true do { let c = byte i of s; if c = 0 then resultis r; string_addchar(r, c); i +:= 1 } } let string_delete(s) be { if s ! string_array <> nil then freevec(s ! string_array); freevec(s); } let start() be { let a; init(); a := string_frombcplstring("abcdefghijklmnopqrstuvwxyz"); string_print(a); outch('\n'); string_addchar(a, '!'); string_setchar(a, 12, 'X'); string_setchar(a, 21, '#'); string_print(a); out(": %d\n", string_length(a)); string_delete(a) }