diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-04-09 13:14:46 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-04-09 13:14:46 -0300 |
commit | 9100f7479afabc4bb2926c619b5ef09693cf9a94 (patch) | |
tree | ed07e9aa37c8f7f4d8282d4d21670c85ea9b6a6c /lauxlib.c | |
parent | 055104f5b6a0264974c5d9f2a55499420a1c9c2a (diff) | |
download | lua-9100f7479afabc4bb2926c619b5ef09693cf9a94.tar.gz lua-9100f7479afabc4bb2926c619b5ef09693cf9a94.tar.bz2 lua-9100f7479afabc4bb2926c619b5ef09693cf9a94.zip |
new implementation for Generic Buffer manipulation (using userdata as
temporary buffer space)
Diffstat (limited to 'lauxlib.c')
-rw-r--r-- | lauxlib.c | 124 |
1 files changed, 53 insertions, 71 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lauxlib.c,v 1.205 2010/03/22 17:28:31 roberto Exp roberto $ | 2 | ** $Id: lauxlib.c,v 1.206 2010/03/29 17:44:31 roberto Exp roberto $ |
3 | ** Auxiliary functions for building Lua libraries | 3 | ** Auxiliary functions for building Lua libraries |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -347,64 +347,40 @@ LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg, | |||
347 | ** ======================================================= | 347 | ** ======================================================= |
348 | */ | 348 | */ |
349 | 349 | ||
350 | 350 | /* | |
351 | #define bufflen(B) ((B)->p - (B)->buffer) | 351 | ** check whether buffer is using a userdata on the stack as a temporary |
352 | #define bufffree(B) ((size_t)(LUAL_BUFFERSIZE - bufflen(B))) | 352 | ** buffer |
353 | 353 | */ | |
354 | #define LIMIT (LUA_MINSTACK/2) | 354 | #define buffonstack(B) ((B)->b != (B)->initb) |
355 | |||
356 | |||
357 | static int emptybuffer (luaL_Buffer *B) { | ||
358 | size_t l = bufflen(B); | ||
359 | if (l == 0) return 0; /* put nothing on stack */ | ||
360 | else { | ||
361 | lua_pushlstring(B->L, B->buffer, l); | ||
362 | B->p = B->buffer; | ||
363 | B->lvl++; | ||
364 | return 1; | ||
365 | } | ||
366 | } | ||
367 | 355 | ||
368 | 356 | ||
369 | static void adjuststack (luaL_Buffer *B) { | 357 | /* |
370 | if (B->lvl > 1) { | 358 | ** returns a pointer to a free area with at least 'sz' bytes |
371 | lua_State *L = B->L; | 359 | */ |
372 | int toget = 1; /* number of levels to concat */ | 360 | LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) { |
373 | size_t toplen = lua_rawlen(L, -1); | 361 | lua_State *L = B->L; |
374 | do { | 362 | if (B->size - B->n < sz) { /* not enough space? */ |
375 | size_t l = lua_rawlen(L, -(toget+1)); | 363 | char *newbuff; |
376 | if (B->lvl - toget + 1 >= LIMIT || toplen > l) { | 364 | size_t newsize = B->size * 2; /* double buffer size */ |
377 | toplen += l; | 365 | if (newsize - B->n < sz) /* not bit enough? */ |
378 | toget++; | 366 | newsize = B->n + sz; |
379 | } | 367 | if (newsize < B->n || newsize - B->n < sz) |
380 | else break; | 368 | luaL_error(L, "string too large"); |
381 | } while (toget < B->lvl); | 369 | newbuff = (char *)lua_newuserdata(L, newsize); /* create larger buffer */ |
382 | lua_concat(L, toget); | 370 | memcpy(newbuff, B->b, B->n); /* move content to new buffer */ |
383 | B->lvl = B->lvl - toget + 1; | 371 | if (buffonstack(B)) |
372 | lua_remove(L, -2); /* remove old buffer */ | ||
373 | B->b = newbuff; | ||
374 | B->size = newsize; | ||
384 | } | 375 | } |
385 | } | 376 | return &B->b[B->n]; |
386 | |||
387 | |||
388 | LUALIB_API char *luaL_prepbuffer (luaL_Buffer *B) { | ||
389 | if (emptybuffer(B)) | ||
390 | adjuststack(B); | ||
391 | return B->buffer; | ||
392 | } | 377 | } |
393 | 378 | ||
394 | 379 | ||
395 | LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { | 380 | LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) { |
396 | while (l) { | 381 | char *b = luaL_prepbuffsize(B, l); |
397 | size_t space = bufffree(B); | 382 | memcpy(b, s, l); |
398 | if (space == 0) { | 383 | luaL_addsize(B, l); |
399 | luaL_prepbuffer(B); | ||
400 | space = LUAL_BUFFERSIZE; /* bufffree(B) == LUAL_BUFFERSIZE */ | ||
401 | } | ||
402 | if (space > l) space = l; | ||
403 | memcpy(B->p, s, space); | ||
404 | B->p += space; | ||
405 | s += space; | ||
406 | l -= space; | ||
407 | } | ||
408 | } | 384 | } |
409 | 385 | ||
410 | 386 | ||
@@ -414,35 +390,41 @@ LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) { | |||
414 | 390 | ||
415 | 391 | ||
416 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { | 392 | LUALIB_API void luaL_pushresult (luaL_Buffer *B) { |
417 | emptybuffer(B); | 393 | lua_State *L = B->L; |
418 | lua_concat(B->L, B->lvl); | 394 | lua_pushlstring(L, B->b, B->n); |
419 | B->lvl = 1; | 395 | if (buffonstack(B)) |
396 | lua_remove(L, -2); /* remove old buffer */ | ||
397 | } | ||
398 | |||
399 | |||
400 | LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) { | ||
401 | luaL_addsize(B, sz); | ||
402 | luaL_pushresult(B); | ||
420 | } | 403 | } |
421 | 404 | ||
422 | 405 | ||
423 | LUALIB_API void luaL_addvalue (luaL_Buffer *B) { | 406 | LUALIB_API void luaL_addvalue (luaL_Buffer *B) { |
424 | lua_State *L = B->L; | 407 | lua_State *L = B->L; |
425 | size_t vl; | 408 | size_t l; |
426 | const char *s = lua_tolstring(L, -1, &vl); | 409 | const char *s = lua_tolstring(L, -1, &l); |
427 | if (vl <= bufffree(B)) { /* fit into buffer? */ | 410 | if (buffonstack(B)) |
428 | memcpy(B->p, s, vl); /* put it there */ | 411 | lua_insert(L, -2); /* put value below buffer */ |
429 | B->p += vl; | 412 | luaL_addlstring(B, s, l); |
430 | lua_pop(L, 1); /* remove from stack */ | 413 | lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */ |
431 | } | ||
432 | else { | ||
433 | if (emptybuffer(B)) | ||
434 | lua_insert(L, -2); /* put buffer before new value */ | ||
435 | B->lvl++; /* add new value into B stack */ | ||
436 | adjuststack(B); | ||
437 | } | ||
438 | } | 414 | } |
439 | 415 | ||
440 | 416 | ||
441 | LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { | 417 | LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) { |
442 | luaL_checkstack(L, LIMIT + LUA_MINSTACK, "no space for new buffer"); | ||
443 | B->L = L; | 418 | B->L = L; |
444 | B->p = B->buffer; | 419 | B->b = B->initb; |
445 | B->lvl = 0; | 420 | B->n = 0; |
421 | B->size = LUAL_BUFFERSIZE; | ||
422 | } | ||
423 | |||
424 | |||
425 | LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) { | ||
426 | luaL_buffinit(L, B); | ||
427 | return luaL_prepbuffsize(B, sz); | ||
446 | } | 428 | } |
447 | 429 | ||
448 | /* }====================================================== */ | 430 | /* }====================================================== */ |