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