OSX/iOS: Fix SDK incompatibility.
[luajit-2.0.git] / src / lib_buffer.c
blobe4ec9d9dd2d195f6baad05c711f10b601e41e5d5
1 /*
2 ** Buffer library.
3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
4 */
6 #define lib_buffer_c
7 #define LUA_LIB
9 #include "lua.h"
10 #include "lauxlib.h"
11 #include "lualib.h"
13 #include "lj_obj.h"
15 #if LJ_HASBUFFER
16 #include "lj_gc.h"
17 #include "lj_err.h"
18 #include "lj_buf.h"
19 #include "lj_str.h"
20 #include "lj_tab.h"
21 #include "lj_udata.h"
22 #include "lj_meta.h"
23 #if LJ_HASFFI
24 #include "lj_ctype.h"
25 #include "lj_cdata.h"
26 #include "lj_cconv.h"
27 #endif
28 #include "lj_strfmt.h"
29 #include "lj_serialize.h"
30 #include "lj_lib.h"
32 /* -- Helper functions ---------------------------------------------------- */
34 /* Check that the first argument is a string buffer. */
35 static SBufExt *buffer_tobuf(lua_State *L)
37 if (!(L->base < L->top && tvisbuf(L->base)))
38 lj_err_argtype(L, 1, "buffer");
39 return bufV(L->base);
42 /* Ditto, but for writers. */
43 static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
45 SBufExt *sbx = buffer_tobuf(L);
46 setsbufXL_(sbx, L);
47 return sbx;
50 #define buffer_toudata(sbx) ((GCudata *)(sbx)-1)
52 /* -- Buffer methods ------------------------------------------------------ */
54 #define LJLIB_MODULE_buffer_method
56 LJLIB_CF(buffer_method_free)
58 SBufExt *sbx = buffer_tobuf(L);
59 lj_bufx_free(L, sbx);
60 L->top = L->base+1; /* Chain buffer object. */
61 return 1;
64 LJLIB_CF(buffer_method_reset) LJLIB_REC(.)
66 SBufExt *sbx = buffer_tobuf(L);
67 lj_bufx_reset(sbx);
68 L->top = L->base+1; /* Chain buffer object. */
69 return 1;
72 LJLIB_CF(buffer_method_skip) LJLIB_REC(.)
74 SBufExt *sbx = buffer_tobuf(L);
75 MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
76 MSize len = sbufxlen(sbx);
77 if (n < len) {
78 sbx->r += n;
79 } else if (sbufiscow(sbx)) {
80 sbx->r = sbx->w;
81 } else {
82 sbx->r = sbx->w = sbx->b;
84 L->top = L->base+1; /* Chain buffer object. */
85 return 1;
88 LJLIB_CF(buffer_method_set) LJLIB_REC(.)
90 SBufExt *sbx = buffer_tobuf(L);
91 GCobj *ref;
92 const char *p;
93 MSize len;
94 #if LJ_HASFFI
95 if (tviscdata(L->base+1)) {
96 CTState *cts = ctype_cts(L);
97 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
98 L->base+1, CCF_ARG(2));
99 len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
100 } else
101 #endif
103 GCstr *str = lj_lib_checkstrx(L, 2);
104 p = strdata(str);
105 len = str->len;
107 lj_bufx_free(L, sbx);
108 lj_bufx_set_cow(L, sbx, p, len);
109 ref = gcV(L->base+1);
110 setgcref(sbx->cowref, ref);
111 lj_gc_objbarrier(L, buffer_toudata(sbx), ref);
112 L->top = L->base+1; /* Chain buffer object. */
113 return 1;
116 LJLIB_CF(buffer_method_put) LJLIB_REC(.)
118 SBufExt *sbx = buffer_tobufw(L);
119 ptrdiff_t arg, narg = L->top - L->base;
120 for (arg = 1; arg < narg; arg++) {
121 cTValue *o = &L->base[arg], *mo = NULL;
122 retry:
123 if (tvisstr(o)) {
124 lj_buf_putstr((SBuf *)sbx, strV(o));
125 } else if (tvisint(o)) {
126 lj_strfmt_putint((SBuf *)sbx, intV(o));
127 } else if (tvisnum(o)) {
128 lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
129 } else if (tvisbuf(o)) {
130 SBufExt *sbx2 = bufV(o);
131 if (sbx2 == sbx) lj_err_arg(L, (int)(arg+1), LJ_ERR_BUFFER_SELF);
132 lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
133 } else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
134 /* Call __tostring metamethod inline. */
135 copyTV(L, L->top++, mo);
136 copyTV(L, L->top++, o);
137 lua_call(L, 1, 1);
138 o = &L->base[arg]; /* The stack may have been reallocated. */
139 copyTV(L, &L->base[arg], L->top-1);
140 L->top = L->base + narg;
141 goto retry; /* Retry with the result. */
142 } else {
143 lj_err_argtype(L, (int)(arg+1), "string/number/__tostring");
145 /* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
147 L->top = L->base+1; /* Chain buffer object. */
148 lj_gc_check(L);
149 return 1;
152 LJLIB_CF(buffer_method_putf) LJLIB_REC(.)
154 SBufExt *sbx = buffer_tobufw(L);
155 lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
156 L->top = L->base+1; /* Chain buffer object. */
157 lj_gc_check(L);
158 return 1;
161 LJLIB_CF(buffer_method_get) LJLIB_REC(.)
163 SBufExt *sbx = buffer_tobuf(L);
164 ptrdiff_t arg, narg = L->top - L->base;
165 if (narg == 1) {
166 narg++;
167 setnilV(L->top++); /* get() is the same as get(nil). */
169 for (arg = 1; arg < narg; arg++) {
170 TValue *o = &L->base[arg];
171 MSize n = tvisnil(o) ? LJ_MAX_BUF :
172 (MSize) lj_lib_checkintrange(L, (int)(arg+1), 0, LJ_MAX_BUF);
173 MSize len = sbufxlen(sbx);
174 if (n > len) n = len;
175 setstrV(L, o, lj_str_new(L, sbx->r, n));
176 sbx->r += n;
178 if (sbx->r == sbx->w && !sbufiscow(sbx)) sbx->r = sbx->w = sbx->b;
179 lj_gc_check(L);
180 return (int)(narg-1);
183 #if LJ_HASFFI
184 LJLIB_CF(buffer_method_putcdata) LJLIB_REC(.)
186 SBufExt *sbx = buffer_tobufw(L);
187 const char *p;
188 MSize len;
189 if (tviscdata(L->base+1)) {
190 CTState *cts = ctype_cts(L);
191 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
192 L->base+1, CCF_ARG(2));
193 } else {
194 lj_err_argtype(L, 2, "cdata");
196 len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
197 lj_buf_putmem((SBuf *)sbx, p, len);
198 L->top = L->base+1; /* Chain buffer object. */
199 return 1;
202 LJLIB_CF(buffer_method_reserve) LJLIB_REC(.)
204 SBufExt *sbx = buffer_tobufw(L);
205 MSize sz = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
206 GCcdata *cd;
207 lj_buf_more((SBuf *)sbx, sz);
208 ctype_loadffi(L);
209 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
210 *(void **)cdataptr(cd) = sbx->w;
211 setcdataV(L, L->top++, cd);
212 setintV(L->top++, sbufleft(sbx));
213 return 2;
216 LJLIB_CF(buffer_method_commit) LJLIB_REC(.)
218 SBufExt *sbx = buffer_tobuf(L);
219 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
220 if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
221 sbx->w += len;
222 L->top = L->base+1; /* Chain buffer object. */
223 return 1;
226 LJLIB_CF(buffer_method_ref) LJLIB_REC(.)
228 SBufExt *sbx = buffer_tobuf(L);
229 GCcdata *cd;
230 ctype_loadffi(L);
231 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
232 *(void **)cdataptr(cd) = sbx->r;
233 setcdataV(L, L->top++, cd);
234 setintV(L->top++, sbufxlen(sbx));
235 return 2;
237 #endif
239 LJLIB_CF(buffer_method_encode) LJLIB_REC(.)
241 SBufExt *sbx = buffer_tobufw(L);
242 cTValue *o = lj_lib_checkany(L, 2);
243 lj_serialize_put(sbx, o);
244 lj_gc_check(L);
245 L->top = L->base+1; /* Chain buffer object. */
246 return 1;
249 LJLIB_CF(buffer_method_decode) LJLIB_REC(.)
251 SBufExt *sbx = buffer_tobufw(L);
252 setnilV(L->top++);
253 sbx->r = lj_serialize_get(sbx, L->top-1);
254 lj_gc_check(L);
255 return 1;
258 LJLIB_CF(buffer_method___gc)
260 SBufExt *sbx = buffer_tobuf(L);
261 lj_bufx_free(L, sbx);
262 return 0;
265 LJLIB_CF(buffer_method___tostring) LJLIB_REC(.)
267 SBufExt *sbx = buffer_tobuf(L);
268 setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
269 lj_gc_check(L);
270 return 1;
273 LJLIB_CF(buffer_method___len) LJLIB_REC(.)
275 SBufExt *sbx = buffer_tobuf(L);
276 setintV(L->top-1, (int32_t)sbufxlen(sbx));
277 return 1;
280 LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
281 LJLIB_PUSH(top-1) LJLIB_SET(__index)
283 /* -- Buffer library functions -------------------------------------------- */
285 #define LJLIB_MODULE_buffer
287 LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
289 LJLIB_CF(buffer_new)
291 MSize sz = 0;
292 int targ = 1;
293 GCtab *env, *dict_str = NULL, *dict_mt = NULL;
294 GCudata *ud;
295 SBufExt *sbx;
296 if (L->base < L->top && !tvistab(L->base)) {
297 targ = 2;
298 if (!tvisnil(L->base))
299 sz = (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
301 if (L->base+targ-1 < L->top) {
302 GCtab *options = lj_lib_checktab(L, targ);
303 cTValue *opt_dict, *opt_mt;
304 opt_dict = lj_tab_getstr(options, lj_str_newlit(L, "dict"));
305 if (opt_dict && tvistab(opt_dict)) {
306 dict_str = tabV(opt_dict);
307 lj_serialize_dict_prep_str(L, dict_str);
309 opt_mt = lj_tab_getstr(options, lj_str_newlit(L, "metatable"));
310 if (opt_mt && tvistab(opt_mt)) {
311 dict_mt = tabV(opt_mt);
312 lj_serialize_dict_prep_mt(L, dict_mt);
315 env = tabref(curr_func(L)->c.env);
316 ud = lj_udata_new(L, sizeof(SBufExt), env);
317 ud->udtype = UDTYPE_BUFFER;
318 /* NOBARRIER: The GCudata is new (marked white). */
319 setgcref(ud->metatable, obj2gco(env));
320 setudataV(L, L->top++, ud);
321 sbx = (SBufExt *)uddata(ud);
322 lj_bufx_init(L, sbx);
323 setgcref(sbx->dict_str, obj2gco(dict_str));
324 setgcref(sbx->dict_mt, obj2gco(dict_mt));
325 if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
326 lj_gc_check(L);
327 return 1;
330 LJLIB_CF(buffer_encode) LJLIB_REC(.)
332 cTValue *o = lj_lib_checkany(L, 1);
333 setstrV(L, L->top++, lj_serialize_encode(L, o));
334 lj_gc_check(L);
335 return 1;
338 LJLIB_CF(buffer_decode) LJLIB_REC(.)
340 GCstr *str = lj_lib_checkstrx(L, 1);
341 setnilV(L->top++);
342 lj_serialize_decode(L, L->top-1, str);
343 lj_gc_check(L);
344 return 1;
347 /* ------------------------------------------------------------------------ */
349 #include "lj_libdef.h"
351 int luaopen_string_buffer(lua_State *L)
353 LJ_LIB_REG(L, NULL, buffer_method);
354 lua_getfield(L, -1, "__tostring");
355 lua_setfield(L, -2, "tostring");
356 LJ_LIB_REG(L, NULL, buffer);
357 return 1;
360 #endif