aboutsummaryrefslogtreecommitdiff
path: root/src/lib_buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib_buffer.c')
-rw-r--r--src/lib_buffer.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/src/lib_buffer.c b/src/lib_buffer.c
new file mode 100644
index 00000000..9aa725b6
--- /dev/null
+++ b/src/lib_buffer.c
@@ -0,0 +1,356 @@
1/*
2** Buffer library.
3** Copyright (C) 2005-2022 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6#define lib_buffer_c
7#define LUA_LIB
8
9#include "lua.h"
10#include "lauxlib.h"
11#include "lualib.h"
12
13#include "lj_obj.h"
14
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"
31
32/* -- Helper functions ---------------------------------------------------- */
33
34/* Check that the first argument is a string buffer. */
35static SBufExt *buffer_tobuf(lua_State *L)
36{
37 if (!(L->base < L->top && tvisbuf(L->base)))
38 lj_err_argtype(L, 1, "buffer");
39 return bufV(L->base);
40}
41
42/* Ditto, but for writers. */
43static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
44{
45 SBufExt *sbx = buffer_tobuf(L);
46 setsbufXL_(sbx, L);
47 return sbx;
48}
49
50#define buffer_toudata(sbx) ((GCudata *)(sbx)-1)
51
52/* -- Buffer methods ------------------------------------------------------ */
53
54#define LJLIB_MODULE_buffer_method
55
56LJLIB_CF(buffer_method_free)
57{
58 SBufExt *sbx = buffer_tobuf(L);
59 lj_bufx_free(L, sbx);
60 L->top = L->base+1; /* Chain buffer object. */
61 return 1;
62}
63
64LJLIB_CF(buffer_method_reset) LJLIB_REC(.)
65{
66 SBufExt *sbx = buffer_tobuf(L);
67 lj_bufx_reset(sbx);
68 L->top = L->base+1; /* Chain buffer object. */
69 return 1;
70}
71
72LJLIB_CF(buffer_method_skip) LJLIB_REC(.)
73{
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 {
80 sbx->r = sbx->w = sbx->b;
81 }
82 L->top = L->base+1; /* Chain buffer object. */
83 return 1;
84}
85
86LJLIB_CF(buffer_method_set) LJLIB_REC(.)
87{
88 SBufExt *sbx = buffer_tobuf(L);
89 GCobj *ref;
90 const char *p;
91 MSize len;
92#if LJ_HASFFI
93 if (tviscdata(L->base+1)) {
94 CTState *cts = ctype_cts(L);
95 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
96 L->base+1, CCF_ARG(2));
97 len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
98 } else
99#endif
100 {
101 GCstr *str = lj_lib_checkstrx(L, 2);
102 p = strdata(str);
103 len = str->len;
104 }
105 lj_bufx_free(L, sbx);
106 lj_bufx_set_cow(L, sbx, p, len);
107 ref = gcV(L->base+1);
108 setgcref(sbx->cowref, ref);
109 lj_gc_objbarrier(L, buffer_toudata(sbx), ref);
110 L->top = L->base+1; /* Chain buffer object. */
111 return 1;
112}
113
114LJLIB_CF(buffer_method_put) LJLIB_REC(.)
115{
116 SBufExt *sbx = buffer_tobufw(L);
117 ptrdiff_t arg, narg = L->top - L->base;
118 for (arg = 1; arg < narg; arg++) {
119 cTValue *o = &L->base[arg], *mo = NULL;
120 retry:
121 if (tvisstr(o)) {
122 lj_buf_putstr((SBuf *)sbx, strV(o));
123 } else if (tvisint(o)) {
124 lj_strfmt_putint((SBuf *)sbx, intV(o));
125 } else if (tvisnum(o)) {
126 lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
127 } else if (tvisbuf(o)) {
128 SBufExt *sbx2 = bufV(o);
129 if (sbx2 == sbx) lj_err_arg(L, arg+1, LJ_ERR_BUFFER_SELF);
130 lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
131 } else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
132 /* Call __tostring metamethod inline. */
133 copyTV(L, L->top++, mo);
134 copyTV(L, L->top++, o);
135 lua_call(L, 1, 1);
136 o = &L->base[arg]; /* The stack may have been reallocated. */
137 copyTV(L, &L->base[arg], L->top-1);
138 L->top = L->base + narg;
139 goto retry; /* Retry with the result. */
140 } else {
141 lj_err_argtype(L, arg+1, "string/number/__tostring");
142 }
143 /* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
144 }
145 L->top = L->base+1; /* Chain buffer object. */
146 lj_gc_check(L);
147 return 1;
148}
149
150LJLIB_CF(buffer_method_putf) LJLIB_REC(.)
151{
152 SBufExt *sbx = buffer_tobufw(L);
153 lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
154 L->top = L->base+1; /* Chain buffer object. */
155 lj_gc_check(L);
156 return 1;
157}
158
159LJLIB_CF(buffer_method_get) LJLIB_REC(.)
160{
161 SBufExt *sbx = buffer_tobuf(L);
162 ptrdiff_t arg, narg = L->top - L->base;
163 if (narg == 1) {
164 narg++;
165 setnilV(L->top++); /* get() is the same as get(nil). */
166 }
167 for (arg = 1; arg < narg; arg++) {
168 TValue *o = &L->base[arg];
169 MSize n = tvisnil(o) ? LJ_MAX_BUF :
170 (MSize) lj_lib_checkintrange(L, arg+1, 0, LJ_MAX_BUF);
171 MSize len = sbufxlen(sbx);
172 if (n > len) n = len;
173 setstrV(L, o, lj_str_new(L, sbx->r, n));
174 sbx->r += n;
175 }
176 if (sbx->r == sbx->w) sbx->r = sbx->w = sbx->b;
177 lj_gc_check(L);
178 return narg-1;
179}
180
181#if LJ_HASFFI
182LJLIB_CF(buffer_method_putcdata) LJLIB_REC(.)
183{
184 SBufExt *sbx = buffer_tobufw(L);
185 const char *p;
186 MSize len;
187 if (tviscdata(L->base+1)) {
188 CTState *cts = ctype_cts(L);
189 lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
190 L->base+1, CCF_ARG(2));
191 } else {
192 lj_err_argtype(L, 2, "cdata");
193 }
194 len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
195 lj_buf_putmem((SBuf *)sbx, p, len);
196 L->top = L->base+1; /* Chain buffer object. */
197 return 1;
198}
199
200LJLIB_CF(buffer_method_reserve) LJLIB_REC(.)
201{
202 SBufExt *sbx = buffer_tobufw(L);
203 MSize sz = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
204 GCcdata *cd;
205 lj_buf_more((SBuf *)sbx, sz);
206 ctype_loadffi(L);
207 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
208 *(void **)cdataptr(cd) = sbx->w;
209 setcdataV(L, L->top++, cd);
210 setintV(L->top++, sbufleft(sbx));
211 return 2;
212}
213
214LJLIB_CF(buffer_method_commit) LJLIB_REC(.)
215{
216 SBufExt *sbx = buffer_tobuf(L);
217 MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
218 if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
219 sbx->w += len;
220 L->top = L->base+1; /* Chain buffer object. */
221 return 1;
222}
223
224LJLIB_CF(buffer_method_ref) LJLIB_REC(.)
225{
226 SBufExt *sbx = buffer_tobuf(L);
227 GCcdata *cd;
228 ctype_loadffi(L);
229 cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
230 *(void **)cdataptr(cd) = sbx->r;
231 setcdataV(L, L->top++, cd);
232 setintV(L->top++, sbufxlen(sbx));
233 return 2;
234}
235#endif
236
237LJLIB_CF(buffer_method_encode) LJLIB_REC(.)
238{
239 SBufExt *sbx = buffer_tobufw(L);
240 cTValue *o = lj_lib_checkany(L, 2);
241 lj_serialize_put(sbx, o);
242 lj_gc_check(L);
243 L->top = L->base+1; /* Chain buffer object. */
244 return 1;
245}
246
247LJLIB_CF(buffer_method_decode) LJLIB_REC(.)
248{
249 SBufExt *sbx = buffer_tobufw(L);
250 setnilV(L->top++);
251 sbx->r = lj_serialize_get(sbx, L->top-1);
252 lj_gc_check(L);
253 return 1;
254}
255
256LJLIB_CF(buffer_method___gc)
257{
258 SBufExt *sbx = buffer_tobuf(L);
259 lj_bufx_free(L, sbx);
260 return 0;
261}
262
263LJLIB_CF(buffer_method___tostring) LJLIB_REC(.)
264{
265 SBufExt *sbx = buffer_tobuf(L);
266 setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
267 lj_gc_check(L);
268 return 1;
269}
270
271LJLIB_CF(buffer_method___len) LJLIB_REC(.)
272{
273 SBufExt *sbx = buffer_tobuf(L);
274 setintV(L->top-1, (int32_t)sbufxlen(sbx));
275 return 1;
276}
277
278LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
279LJLIB_PUSH(top-1) LJLIB_SET(__index)
280
281/* -- Buffer library functions -------------------------------------------- */
282
283#define LJLIB_MODULE_buffer
284
285LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
286
287LJLIB_CF(buffer_new)
288{
289 MSize sz = 0;
290 int targ = 1;
291 GCtab *env, *dict_str = NULL, *dict_mt = NULL;
292 GCudata *ud;
293 SBufExt *sbx;
294 if (L->base < L->top && !tvistab(L->base)) {
295 targ = 2;
296 if (!tvisnil(L->base))
297 sz = (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
298 }
299 if (L->base+targ-1 < L->top) {
300 GCtab *options = lj_lib_checktab(L, targ);
301 cTValue *opt_dict, *opt_mt;
302 opt_dict = lj_tab_getstr(options, lj_str_newlit(L, "dict"));
303 if (opt_dict && tvistab(opt_dict)) {
304 dict_str = tabV(opt_dict);
305 lj_serialize_dict_prep_str(L, dict_str);
306 }
307 opt_mt = lj_tab_getstr(options, lj_str_newlit(L, "metatable"));
308 if (opt_mt && tvistab(opt_mt)) {
309 dict_mt = tabV(opt_mt);
310 lj_serialize_dict_prep_mt(L, dict_mt);
311 }
312 }
313 env = tabref(curr_func(L)->c.env);
314 ud = lj_udata_new(L, sizeof(SBufExt), env);
315 ud->udtype = UDTYPE_BUFFER;
316 /* NOBARRIER: The GCudata is new (marked white). */
317 setgcref(ud->metatable, obj2gco(env));
318 setudataV(L, L->top++, ud);
319 sbx = (SBufExt *)uddata(ud);
320 lj_bufx_init(L, sbx);
321 setgcref(sbx->dict_str, obj2gco(dict_str));
322 setgcref(sbx->dict_mt, obj2gco(dict_mt));
323 if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
324 return 1;
325}
326
327LJLIB_CF(buffer_encode) LJLIB_REC(.)
328{
329 cTValue *o = lj_lib_checkany(L, 1);
330 setstrV(L, L->top++, lj_serialize_encode(L, o));
331 lj_gc_check(L);
332 return 1;
333}
334
335LJLIB_CF(buffer_decode) LJLIB_REC(.)
336{
337 GCstr *str = lj_lib_checkstrx(L, 1);
338 setnilV(L->top++);
339 lj_serialize_decode(L, L->top-1, str);
340 return 1;
341}
342
343/* ------------------------------------------------------------------------ */
344
345#include "lj_libdef.h"
346
347int luaopen_string_buffer(lua_State *L)
348{
349 LJ_LIB_REG(L, NULL, buffer_method);
350 lua_getfield(L, -1, "__tostring");
351 lua_setfield(L, -2, "tostring");
352 LJ_LIB_REG(L, NULL, buffer);
353 return 1;
354}
355
356#endif